Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 09 Jun 2014 18:17:11 -0400
changeset 187756 c6e7a0fb4b89a55018011772dc7c9d39b77f1c9d
parent 187755 bb24d6b30117f179a0ee71ae61842e19d48e0756 (current diff)
parent 187746 fc70d6d9a9b07beb445ff15a0a56566322a50c1b (diff)
child 187757 029ab16fd64cadabee8be504aaee29b2821a60fe
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone33.0a1
Merge m-c to b2g-inbound. a=merge
--- a/.hgtags
+++ b/.hgtags
@@ -96,8 +96,9 @@ d7ce9089999719d5186595d160f25123a4e63e39
 8d3810543edccf4fbe458178b88dd4a6e420b010 FIREFOX_AURORA_24_BASE
 ad0ae007aa9e03cd74e9005cd6652e544139b3b5 FIREFOX_AURORA_25_BASE
 2520866d58740851d862c7c59246a4e3f8b4a176 FIREFOX_AURORA_26_BASE
 05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE
 9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
 ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE
 83c9853e136451474dfa6d1aaa60a7fca7d2d83a FIREFOX_AURORA_30_BASE
 cfde3603b0206e119abea76fdd6e134b634348f1 FIREFOX_AURORA_31_BASE
+16f3cac5e8fe471e12f76d6a94a477b14e78df7c FIREFOX_AURORA_32_BASE
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,21 +1,21 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=32.0a1
+MOZ_APP_VERSION=33.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_UA_OS_AGNOSTIC=1
 
-MOZ_B2G_VERSION=2.0.0.0-prerelease
+MOZ_B2G_VERSION=2.1.0.0-prerelease
 MOZ_B2G_OS_NAME=Boot2Gecko
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1499,16 +1499,24 @@ pref("pdfjs.previousHandler.alwaysAskBef
 pref("shumway.disabled", true);
 #endif
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
+#ifdef MOZ_LOOP
+pref("loop.server", "https://loop.services.mozilla.com");
+pref("loop.do_not_disturb", false);
+#endif
+
+// serverURL to be assigned by services team
+pref("services.push.serverURL", "wss://push.services.mozilla.com/");
+
 // Default social providers
 pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Share\",\"shareURL\":\"https://www.facebook.com/sharer/sharer.php?u=%{url}\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"icon32URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAADbklEQVRYCc1Xv08UQRj99tctexAuCEFjRE0kGBEtLDSGqIWNxkYKbTAxNlY2JhaGWltNtNFeKgsKKxITK43/gCYW+IsoRhA4D47bH7fn9+bcvdm5JR7sefolC3Ozu9978+bNN7PayUv3HN3umdY0Y6IWBtSJ0HSTarXqTOiuTep6Lj+tdxAcA8RAgSmwdd2aCDs0clldYALb/FvgYVhjmfliVA2XpjEgWo0Attn42Z6WH1RFor5ehwo9XQIUZMoVn4qlCoVMSo62EvD8Kh0b3U2Xz43R2PBO6mUCGDlAf65V6MadZzT/rUimoccc2kYA4BfPHqJb105RzjJigKhRq9kEJUBIjgYVuXeL7SAI6eD+Abp5dTwVHOmEHxT50d8WBYJqSOdPj5BjW8gZR8UNqFR2xagx/65XFYaMH+BGWwiYpi4UkBPPLxTp9v1Z+lHc4DWvCQXWmIy6EjITgKowVd5Jjv7N3Hd6y5esigoOwpkJIAmMpZpLJGdiaaC4F0UmAj6bD84GCEwmB/qxMmRilmnwb/mpjAocHh4UEoNAt5NLZB7oy9OJo0PxqkAtePdhiSqunyC1LQUwWMPQaOr6GRre258Ajn4cP7KHcEXhsxpXbj+lT19X2TMNGTLVAcjcalS8gDwsQ2UOMhH4k8FkcrEn5E5ub2sKohxLK2VR77Hl9RUcsrgeRIEiVOT6z+tDbIeLy+vk+kGTCbXxycet6xhl//3f6bJEkdHYhA+mLtDIvoH4ieev5+juoxdk5+pjhALYEdXIpEB5w+NlSKSzqVQ/+H7IO6BLtl3fngGMiqhGJgIwlM6qpyUGFjySdk8m0Zg0ubeD7X9OIDEFajltRQgUJaUKx69tdgaQa0FMADuahZPMFtcEwNPm2hA7ZI5sK4aoE2NvYI+o8hkCIe7CwTv68zS0q9Dk5vpbm/8FXxitSzmMFHpsGj0wyLUheTwD2Y9fVgh1Ae0EPUgD9241ZEnld+v5kgnVZ/8fE0brVh5BK+1oCqKKF72Dk7HwBsssB/pklU1dfChy3S659H5+uelgIb+8WRv1/uGTV9Sdb5wJFlfW6fPCalMhwhSU1j2xKwKbP838GcOwJja4TqO0bjdmXxYTy1EYjFdCWoCEYZhseH/GDL3yJPHnuW6YmT7P1SlIA4768Hke4vOcsX8BE346lLHhDUQAAAAASUVORK5CYII=\", \"icon64URL\":\"data:image/png;base64,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\", \"description\":\"Easily share the web to your Facebook friends.\",\"author\":\"Facebook\",\"homepageURL\":\"https://www.facebook.com\",\"builtin\":\"true\",\"version\":1}");
 
 pref("social.sidebar.unload_timeout_ms", 10000);
 
 pref("dom.identity.enabled", false);
 
 // Turn on the CSP 1.0 parser for Content Security Policy headers
new file mode 100644
--- /dev/null
+++ b/browser/base/content/browser-loop.js
@@ -0,0 +1,68 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// the "exported" symbols
+let LoopUI;
+
+XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm");
+
+
+(function() {
+
+  LoopUI = {
+    /**
+     * Opens the panel for Loop and sizes it appropriately.
+     *
+     * @param {event} event The event opening the panel, used to anchor
+     *                      the panel to the button which triggers it.
+     */
+    openCallPanel: function(event) {
+      let panel = document.getElementById("loop-panel");
+      let anchor = event.target;
+      let iframe = document.getElementById("loop-panel-frame");
+
+      if (!iframe) {
+        // XXX This should be using SharedFrame (bug 1011392 may do this).
+        iframe = document.createElement("iframe");
+        iframe.setAttribute("id", "loop-panel-frame");
+        iframe.setAttribute("type", "content");
+        iframe.setAttribute("class", "loop-frame social-panel-frame");
+        iframe.setAttribute("flex", "1");
+        panel.appendChild(iframe);
+      }
+
+      // We inject in DOMContentLoaded as that is before any scripts have tun.
+      iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
+        iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
+        injectLoopAPI(iframe.contentWindow);
+
+        // We use loopPanelInitialized so that we know we've finished localising before
+        // sizing the panel.
+        iframe.contentWindow.addEventListener("loopPanelInitialized",
+          function documentLoaded() {
+            iframe.contentWindow.removeEventListener("loopPanelInitialized",
+                                                     documentLoaded, true);
+            // XXX We end up with the wrong size here, so this
+            // needs further investigation (bug 1011394).
+            sizeSocialPanelToContent(panel, iframe);
+          }, true);
+
+      }, true);
+
+      iframe.setAttribute("src", "about:looppanel");
+      panel.hidden = false;
+      panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
+    },
+
+    /**
+     * Triggers the initialization of the loop service.  Called by
+     * delayedStartup.
+     */
+    initialize: function() {
+      MozLoopService.initialize();
+    },
+
+  };
+})();
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -167,16 +167,19 @@ let gInitialPages = [
   "about:sessionrestore"
 ];
 
 #include browser-addons.js
 #include browser-customization.js
 #include browser-feeds.js
 #include browser-fullScreen.js
 #include browser-fullZoom.js
+#ifdef MOZ_LOOP
+#include browser-loop.js
+#endif
 #include browser-places.js
 #include browser-plugins.js
 #include browser-safebrowsing.js
 #include browser-social.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
 #include browser-thumbnails.js
 #include browser-webrtcUI.js
@@ -1177,16 +1180,20 @@ var gBrowserInit = {
     gSyncUI.init();
     gFxAccounts.init();
 #endif
 
 #ifdef MOZ_DATA_REPORTING
     gDataNotificationInfoBar.init();
 #endif
 
+#ifdef MOZ_LOOP
+    LoopUI.initialize();
+#endif
+
     gBrowserThumbnails.init();
 
     // Add Devtools menuitems and listeners
     gDevToolsBrowser.registerBrowserWindow(window);
 
     window.addEventListener("mousemove", MousePosTracker, false);
     window.addEventListener("dragover", MousePosTracker, false);
 
@@ -5306,18 +5313,18 @@ function stylesheetSwitchAll(contentWind
 function setStyleDisabled(disabled) {
   if (disabled)
     gPageStyleMenu.disableStyle();
 }
 
 
 var LanguageDetectionListener = {
   init: function() {
-    window.messageManager.addMessageListener("LanguageDetection:Result", msg => {
-      Translation.languageDetected(msg.target, msg.data);
+    window.messageManager.addMessageListener("Translation:DocumentState", msg => {
+      Translation.documentStateReceived(msg.target, msg.data);
     });
   }
 };
 
 
 var BrowserOffline = {
   _inited: false,
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -221,17 +221,17 @@
         <vbox flex="1">
           <label id="UITourTooltipTitle" flex="1"/>
           <description id="UITourTooltipDescription" flex="1"/>
         </vbox>
       </hbox>
       <hbox id="UITourTooltipButtons" flex="1" align="center"/>
      </vbox>
     </panel>
-    <!-- type="default" forces frames to be created so that the panel's size can be determined --> 
+    <!-- type="default" forces frames to be created so that the panel's size can be determined -->
     <panel id="UITourHighlightContainer"
            type="default"
            hidden="true"
            noautofocus="true"
            noautohide="true"
            flip="none"
            consumeoutsideclicks="false"
            mousethrough="always">
@@ -262,16 +262,24 @@
            side="right"
            type="arrow"
            hidden="true"
            flip="slide"
            rolluponmousewheel="true"
            noautofocus="true"
            position="topcenter topright"/>
 
+#ifdef MOZ_LOOP
+    <panel id="loop-panel"
+           class="loop-panel social-panel"
+           type="arrow"
+           orient="horizontal"
+           hidden="true"/>
+#endif
+
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
       <menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
                 accesskey="&customizeMenu.moveToPanel.accesskey;"
                 label="&customizeMenu.moveToPanel.label;"
                 class="customize-context-moveToPanel"/>
       <menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
                 accesskey="&customizeMenu.removeFromToolbar.accesskey;"
@@ -630,17 +638,21 @@
            Should you need to add items to the toolbar here, make sure to also add them
            to the default placements of buttons in CustomizableUI.jsm, so the
            customization code doesn't get confused.
       -->
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              aria-label="&navbarCmd.label;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="small"
+#ifdef MOZ_LOOP
+             defaultset="urlbar-container,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,loop-call-button,social-share-button,social-toolbar-item"
+#else
              defaultset="urlbar-container,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,social-share-button,social-toolbar-item"
+#endif
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
              overflowpanel="widget-overflow"
              context="toolbar-context-menu">
 
       <hbox id="nav-bar-customization-target" flex="1">
@@ -763,16 +775,30 @@
                        tooltiptext="&webrtcIndicatorButton.tooltip;"
                        cui-areatype="toolbar"
                        overflows="false">
           <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
                      onpopuphiding="WebrtcIndicator.clearPopup(this);"
                      oncommand="WebrtcIndicator.menuCommand(event.target);"/>
         </toolbarbutton>
 
+#ifdef MOZ_LOOP
+        <!-- XXX Bug 1013989 will provide a label for the button -->
+        <toolbarbutton id="loop-call-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       persist="class"
+                       removable="true"
+                       tooltiptext="&loopCallButton.tooltip;"
+                       oncommand="LoopUI.openCallPanel(event);"
+                       cui-areatype="toolbar"
+                       overflows="false"
+                       >
+        </toolbarbutton>
+#endif
+
         <toolbarbutton id="bookmarks-menu-button"
                        class="toolbarbutton-1 chromeclass-toolbar-additional"
                        persist="class"
                        removable="true"
                        type="menu-button"
                        label="&bookmarksMenuButton.label;"
                        tooltip="dynamic-shortcut-tooltip"
                        anchor="dropmarker"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3062,17 +3062,20 @@
       </method>
 
       <constructor>
         <![CDATA[
           let browserStack = document.getAnonymousElementByAttribute(this, "anonid", "browserStack");
           this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
 
           this.mCurrentTab = this.tabContainer.firstChild;
-          let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
+          const nsIEventListenerService =
+            Components.interfaces.nsIEventListenerService;
+          let els = Components.classes["@mozilla.org/eventlistenerservice;1"]
+                              .getService(nsIEventListenerService);
           els.addSystemEventListener(document, "keydown", this, false);
           els.addSystemEventListener(document, "keypress", this, false);
           window.addEventListener("sizemodechange", this, false);
 
           var uniqueId = this._generateUniquePanelID();
           this.mPanelContainer.childNodes[0].id = uniqueId;
           this.mCurrentTab.linkedPanel = uniqueId;
           this.mCurrentTab._tPos = 0;
@@ -3142,17 +3145,20 @@
               delete browser.registeredOpenURI;
             }
             browser.webProgress.removeProgressListener(this.mTabFilters[i]);
             this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
             this.mTabFilters[i] = null;
             this.mTabListeners[i].destroy();
             this.mTabListeners[i] = null;
           }
-          let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
+          const nsIEventListenerService =
+            Components.interfaces.nsIEventListenerService;
+          let els = Components.classes["@mozilla.org/eventlistenerservice;1"]
+                              .getService(nsIEventListenerService);
           els.removeSystemEventListener(document, "keydown", this, false);
           els.removeSystemEventListener(document, "keypress", this, false);
           window.removeEventListener("sizemodechange", this, false);
 
           if (gMultiProcessBrowser) {
             messageManager.removeMessageListener("DOMTitleChanged", this);
             messageManager.removeMessageListener("contextmenu", this);
           }
--- a/browser/base/content/test/general/browser_parsable_css.js
+++ b/browser/base/content/test/general/browser_parsable_css.js
@@ -9,16 +9,17 @@
  * matching the offending error. If an object has multiple regex criteria, they
  * ALL need to match an error in order for that error not to cause a test
  * failure. */
 const kWhitelist = [
   {sourceName: /cleopatra.*(tree|ui)\.css/i}, /* Cleopatra is imported as-is, see bug 1004421 */
   {sourceName: /codemirror\.css/i}, /* CodeMirror is imported as-is, see bug 1004423 */
   {sourceName: /web\/viewer\.css/i, errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i }, /* PDFjs is futureproofing its pseudoselectors, and those rules are dropped. */
   {sourceName: /aboutaccounts\/(main|normalize)\.css/i}, /* Tracked in bug 1004428 */
+  {sourceName: /otcdn\/webrtc\/.*\.css$/i /* TokBox SDK assets, see bug 1003029 */}
 ];
 
 /**
  * Check if an error should be ignored due to matching one of the whitelist
  * objects defined in kWhitelist
  *
  * @param aErrorObject the error to check
  * @return true if the error should be ignored, false otherwise.
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -92,16 +92,26 @@ static RedirEntry kRedirMap[] = {
     nsIAboutModule::ALLOW_SCRIPT },
 #endif
   { "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "app-manager", "chrome://browser/content/devtools/app-manager/index.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xul",
     nsIAboutModule::ALLOW_SCRIPT },
+#ifdef MOZ_LOOP
+  { "loopconversation", "chrome://browser/content/loop/conversation.html",
+    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT },
+  { "looppanel", "chrome://browser/content/loop/panel.html",
+    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT },
+#endif
 };
 static const int kRedirTotal = ArrayLength(kRedirMap);
 
 static nsAutoCString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsAutoCString path;
   aURI->GetPath(path);
@@ -114,17 +124,17 @@ GetAboutModuleName(nsIURI *aURI)
   if (f >= 0)
     path.SetLength(f);
 
   ToLowerCase(path);
   return path;
 }
 
 NS_IMETHODIMP
-AboutRedirector::NewChannel(nsIURI *aURI, nsIChannel **result) 
+AboutRedirector::NewChannel(nsIURI *aURI, nsIChannel **result)
 {
   NS_ENSURE_ARG_POINTER(aURI);
   NS_ASSERTION(result, "must not be null");
 
   nsAutoCString path = GetAboutModuleName(aURI);
 
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -107,16 +107,20 @@ static const mozilla::Module::ContractID
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "accounts", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #ifdef MOZ_SERVICES_HEALTHREPORT
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "app-manager", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+#ifdef MOZ_LOOP
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+#endif
 #if defined(XP_WIN)
     { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
 #elif defined(XP_MACOSX)
     { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
 #endif
     { nullptr }
 };
 
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -195,16 +195,19 @@ let CustomizableUIInternal = {
       overflowable: true,
       defaultPlacements: [
         "urlbar-container",
         "search-container",
         "webrtc-status-button",
         "bookmarks-menu-button",
         "downloads-button",
         "home-button",
+#ifdef MOZ_LOOP
+        "loop-call-button",
+#endif
         "social-share-button",
       ],
       defaultCollapsed: false,
     }, true);
 #ifndef XP_MACOSX
     this.registerArea(CustomizableUI.AREA_MENUBAR, {
       legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -0,0 +1,170 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource:///modules/loop/MozLoopService.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
+  "resource://gre/modules/MozSocialAPI.jsm");
+
+this.EXPORTED_SYMBOLS = ["injectLoopAPI"];
+
+/**
+ * Inject the loop API into the given window.  The caller must be sure the
+ * window is a loop content window (eg, a panel, chatwindow, or similar).
+ *
+ * See the documentation on the individual functions for details of the API.
+ *
+ * @param {nsIDOMWindow} targetWindow The content window to attach the API.
+ */
+function injectLoopAPI(targetWindow) {
+  let api = {
+    /**
+     * Sets and gets the "do not disturb" mode activation flag.
+     */
+    doNotDisturb: {
+      enumerable: true,
+      configurable: true,
+      get: function() {
+        return MozLoopService.doNotDisturb;
+      },
+      set: function(aFlag) {
+        MozLoopService.doNotDisturb = aFlag;
+      }
+    },
+
+    /**
+     * Returns the url for the Loop server from preferences.
+     *
+     * @return {String} The Loop server url
+     */
+    serverUrl: {
+      enumerable: true,
+      configurable: true,
+      get: function() {
+        return Services.prefs.getCharPref("loop.server");
+      }
+    },
+
+    /**
+     * Returns the current locale of the browser.
+     *
+     * @returns {String} The locale string
+     */
+    locale: {
+      enumerable: true,
+      configurable: true,
+      get: function() {
+        return MozLoopService.locale;
+      }
+    },
+
+    /**
+     * Returns translated strings associated with an element. Designed
+     * for use with l10n.js
+     *
+     * @param {String} key The element id
+     * @returns {Object} A JSON string containing the localized
+     *                   attribute/value pairs for the element.
+     */
+    getStrings: {
+      enumerable: true,
+      configurable: true,
+      writable: true,
+      value: function(key) {
+        return MozLoopService.getStrings(key);
+      }
+    },
+
+    /**
+     * Call to ensure that any necessary registrations for the Loop Service
+     * have taken place.
+     *
+     * Callback parameters:
+     * - err null on successful registration, non-null otherwise.
+     *
+     * @param {Function} callback Will be called once registration is complete,
+     *                            or straight away if registration has already
+     *                            happened.
+     */
+    ensureRegistered: {
+      enumerable: true,
+      configurable: true,
+      writable: true,
+      value: function(callback) {
+        // We translate from a promise to a callback, as we can't pass promises from
+        // Promise.jsm across the priv versus unpriv boundary.
+        return MozLoopService.register().then(() => {
+          callback(null);
+        }, err => {
+          callback(err);
+        });
+      }
+    },
+
+    /**
+     * Used to note a call url expiry time. If the time is later than the current
+     * latest expiry time, then the stored expiry time is increased. For times
+     * sooner, this function is a no-op; this ensures we always have the latest
+     * expiry time for a url.
+     *
+     * This is used to determine whether or not we should be registering with the
+     * push server on start.
+     *
+     * @param {Integer} expiryTimeSeconds The seconds since epoch of the expiry time
+     *                                    of the url.
+     */
+    noteCallUrlExpiry: {
+      enumerable: true,
+      configurable: true,
+      writable: true,
+      value: function(expiryTimeSeconds) {
+        MozLoopService.noteCallUrlExpiry(expiryTimeSeconds);
+      }
+    },
+
+    /**
+     * Return any preference under "loop." that's coercible to a character
+     * preference.
+     *
+     * @param {String} prefName The name of the pref without the preceding
+     * "loop."
+     *
+     * Any errors thrown by the Mozilla pref API are logged to the console
+     * and cause null to be returned. This includes the case of the preference
+     * not being found.
+     *
+     * @return {String} on success, null on error
+     */
+    getLoopCharPref: {
+      enumerable: true,
+      configurable: true,
+      writable: true,
+      value: function(prefName) {
+        return MozLoopService.getLoopCharPref(prefName);
+      }
+    }
+  };
+
+  let contentObj = Cu.createObjectIn(targetWindow);
+  Object.defineProperties(contentObj, api);
+  Cu.makeObjectPropsNormal(contentObj);
+
+  targetWindow.navigator.wrappedJSObject.__defineGetter__("mozLoop", function() {
+    // We do this in a getter, so that we create these objects
+    // only on demand (this is a potential concern, since
+    // otherwise we might add one per iframe, and keep them
+    // alive for as long as the window is alive).
+    delete targetWindow.navigator.wrappedJSObject.mozLoop;
+    return targetWindow.navigator.wrappedJSObject.mozLoop = contentObj;
+  });
+
+  // Handle window.close correctly on the panel and chatbox.
+  hookWindowCloseForPanelClose(targetWindow);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/MozLoopService.jsm
@@ -0,0 +1,593 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
+
+this.EXPORTED_SYMBOLS = ["MozLoopService"];
+
+XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI",
+  "resource:///modules/loop/MozLoopAPI.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Chat", "resource:///modules/Chat.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
+                                  "resource://services-common/utils.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
+                                  "resource://services-crypto/utils.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "HAWKAuthenticatedRESTRequest",
+                                  "resource://services-common/hawkrequest.js");
+
+/**
+ * We don't have push notifications on desktop currently, so this is a
+ * workaround to get them going for us.
+ *
+ * XXX Handle auto-reconnections if connection fails for whatever reason
+ * (bug 1013248).
+ */
+let PushHandlerHack = {
+  // This is the uri of the push server.
+  pushServerUri: Services.prefs.getCharPref("services.push.serverURL"),
+  // This is the channel id we're using for notifications
+  channelID: "8b1081ce-9b35-42b5-b8f5-3ff8cb813a50",
+  // Stores the push url if we're registered and we have one.
+  pushUrl: undefined,
+
+  /**
+   * Call to start the connection to the push socket server. On
+   * connection, it will automatically say hello and register the channel
+   * id with the server.
+   *
+   * Register callback parameters:
+   * - {String|null} err: Encountered error, if any
+   * - {String} url: The push url obtained from the server
+   *
+   * @param {Function} registerCallback Callback to be called once we are
+   *                     registered.
+   * @param {Function} notificationCallback Callback to be called when a
+   *                     push notification is received.
+   */
+  initialize: function(registerCallback, notificationCallback) {
+    if (Services.io.offline) {
+      registerCallback("offline");
+      return;
+    }
+
+    this._registerCallback = registerCallback;
+    this._notificationCallback = notificationCallback;
+
+    this.websocket = Cc["@mozilla.org/network/protocol;1?name=wss"]
+                       .createInstance(Ci.nsIWebSocketChannel);
+
+    this.websocket.protocol = "push-notification";
+
+    var pushURI = Services.io.newURI(this.pushServerUri, null, null);
+    this.websocket.asyncOpen(pushURI, this.pushServerUri, this, null);
+  },
+
+  /**
+   * Listener method, handles the start of the websocket stream.
+   * Sends a hello message to the server.
+   *
+   * @param {nsISupports} aContext Not used
+   */
+  onStart: function() {
+    var helloMsg = { messageType: "hello", uaid: "", channelIDs: [] };
+    this.websocket.sendMsg(JSON.stringify(helloMsg));
+  },
+
+  /**
+   * Listener method, called when the websocket is closed.
+   *
+   * @param {nsISupports} aContext Not used
+   * @param {nsresult} aStatusCode Reason for stopping (NS_OK = successful)
+   */
+  onStop: function(aContext, aStatusCode) {
+    // XXX We really should be handling auto-reconnect here, this will be
+    // implemented in bug 994151. For now, just log a warning, so that a
+    // developer can find out it has happened and not get too confused.
+    Cu.reportError("Loop Push server web socket closed! Code: " + aStatusCode);
+    this.pushUrl = undefined;
+  },
+
+  /**
+   * Listener method, called when the websocket is closed by the server.
+   * If there are errors, onStop may be called without ever calling this
+   * method.
+   *
+   * @param {nsISupports} aContext Not used
+   * @param {integer} aCode the websocket closing handshake close code
+   * @param {String} aReason the websocket closing handshake close reason
+   */
+  onServerClose: function(aContext, aCode) {
+    // XXX We really should be handling auto-reconnect here, this will be
+    // implemented in bug 994151. For now, just log a warning, so that a
+    // developer can find out it has happened and not get too confused.
+    Cu.reportError("Loop Push server web socket closed (server)! Code: " + aCode);
+    this.pushUrl = undefined;
+  },
+
+  /**
+   * Listener method, called when the websocket receives a message.
+   *
+   * @param {nsISupports} aContext Not used
+   * @param {String} aMsg The message data
+   */
+  onMessageAvailable: function(aContext, aMsg) {
+    var msg = JSON.parse(aMsg);
+
+    switch(msg.messageType) {
+      case "hello":
+        this._registerChannel();
+        break;
+      case "register":
+        this.pushUrl = msg.pushEndpoint;
+        this._registerCallback(null, this.pushUrl);
+        break;
+      case "notification":
+        msg.updates.forEach(function(update) {
+          if (update.channelID === this.channelID) {
+            this._notificationCallback(update.version);
+          }
+        }.bind(this));
+        break;
+    }
+  },
+
+  /**
+   * Handles registering a service
+   */
+  _registerChannel: function() {
+    this.websocket.sendMsg(JSON.stringify({
+      messageType: "register",
+      channelID: this.channelID
+    }));
+  }
+};
+
+/**
+ * Internal helper methods and state
+ *
+ * The registration is a two-part process. First we need to connect to
+ * and register with the push server. Then we need to take the result of that
+ * and register with the Loop server.
+ */
+let MozLoopServiceInternal = {
+  // The uri of the Loop server.
+  loopServerUri: Services.prefs.getCharPref("loop.server"),
+
+  // The current deferred for the registration process. This is set if in progress
+  // or the registration was successful. This is null if a registration attempt was
+  // unsuccessful.
+  _registeredDeferred: null,
+
+  /**
+   * The initial delay for push registration. This ensures we don't start
+   * kicking off straight after browser startup, just a few seconds later.
+   */
+  get initialRegistrationDelayMilliseconds() {
+    try {
+      // Let a pref override this for developer & testing use.
+      return Services.prefs.getIntPref("loop.initialDelay");
+    } catch (x) {
+      // Default to 5 seconds
+      return 5000;
+    }
+    return initialDelay;
+  },
+
+  /**
+   * Gets the current latest expiry time for urls.
+   *
+   * In seconds since epoch.
+   */
+  get expiryTimeSeconds() {
+    try {
+      return Services.prefs.getIntPref("loop.urlsExpiryTimeSeconds");
+    } catch (x) {
+      // It is ok for the pref not to exist.
+      return 0;
+    }
+  },
+
+  /**
+   * Sets the expiry time to either the specified time, or keeps it the same
+   * depending on which is latest.
+   */
+  set expiryTimeSeconds(time) {
+    if (time > this.expiryTimeSeconds) {
+      Services.prefs.setIntPref("loop.urlsExpiryTimeSeconds", time);
+    }
+  },
+
+  /**
+   * Returns true if the expiry time is in the future.
+   */
+  urlExpiryTimeIsInFuture: function() {
+    return this.expiryTimeSeconds * 1000 > Date.now();
+  },
+
+  /**
+   * Retrieves MozLoopService "do not disturb" pref value.
+   *
+   * @return {Boolean} aFlag
+   */
+  get doNotDisturb() {
+    return Services.prefs.getBoolPref("loop.do_not_disturb");
+  },
+
+  /**
+   * Sets MozLoopService "do not disturb" pref value.
+   *
+   * @param {Boolean} aFlag
+   */
+  set doNotDisturb(aFlag) {
+    Services.prefs.setBoolPref("loop.do_not_disturb", Boolean(aFlag));
+  },
+
+  /**
+   * Starts registration of Loop with the push server, and then will register
+   * with the Loop server. It will return early if already registered.
+   *
+   * @returns {Promise} a promise that is resolved with no params on completion, or
+   *          rejected with an error code or string.
+   */
+  promiseRegisteredWithServers: function() {
+    if (this._registeredDeferred) {
+      return this._registeredDeferred.promise;
+    }
+
+    this._registeredDeferred = Promise.defer();
+    // We grab the promise early in case .initialize or its results sets
+    // it back to null on error.
+    let result = this._registeredDeferred.promise;
+
+    PushHandlerHack.initialize(this.onPushRegistered.bind(this),
+                               this.onHandleNotification.bind(this));
+
+    return result;
+  },
+
+  /**
+   * Derives hawk credentials for the given token and context.
+   *
+   * @param {String} tokenHex The token value in hex.
+   * @param {String} context  The context for the token.
+   */
+  deriveHawkCredentials: function(tokenHex, context) {
+    const PREFIX_NAME = "identity.mozilla.com/picl/v1/";
+
+    let token = CommonUtils.hexToBytes(tokenHex);
+    let keyWord = CommonUtils.stringToBytes(PREFIX_NAME + context);
+
+    // XXX Using 2 * 32 for now to be in sync with client.js, but we might
+    // want to make this 3 * 32 to allow for extra, if we start using the extra
+    // field.
+    let out = CryptoUtils.hkdf(token, undefined, keyWord, 2 * 32);
+
+    return {
+      algorithm: "sha256",
+      key: out.slice(32, 64),
+      id: CommonUtils.bytesAsHex(out.slice(0, 32))
+    };
+  },
+
+  /**
+   * Callback from PushHandlerHack - The push server has been registered
+   * and has given us a push url.
+   *
+   * @param {String} pushUrl The push url given by the push server.
+   */
+  onPushRegistered: function(err, pushUrl) {
+    if (err) {
+      this._registeredDeferred.reject(err);
+      this._registeredDeferred = null;
+      return;
+    }
+
+    this.registerWithLoopServer(pushUrl);
+  },
+
+  /**
+   * Registers with the Loop server.
+   *
+   * @param {String} pushUrl The push url given by the push server.
+   * @param {Boolean} noRetry Optional, don't retry if authentication fails.
+   */
+  registerWithLoopServer: function(pushUrl, noRetry) {
+    let sessionToken;
+    try {
+      sessionToken = Services.prefs.getCharPref("loop.hawk-session-token");
+    } catch (x) {
+      // It is ok for this not to exist, we'll default to sending no-creds
+    }
+
+    let credentials;
+    if (sessionToken) {
+      credentials = this.deriveHawkCredentials(sessionToken, "sessionToken");
+    }
+
+    let uri = Services.io.newURI(this.loopServerUri, null, null).resolve("/registration");
+    this.loopXhr = new HAWKAuthenticatedRESTRequest(uri, credentials);
+
+    this.loopXhr.dispatch('POST', { simple_push_url: pushUrl }, (error) => {
+      if (this.loopXhr.response.status == 401) {
+        if (this.urlExpiryTimeIsInFuture()) {
+          // XXX Should this be reported to the user is a visible manner?
+          Cu.reportError("Loop session token is invalid, all previously "
+                         + "generated urls will no longer work.");
+        }
+
+        // Authorization failed, invalid token, we need to try again with a new token.
+        Services.prefs.clearUserPref("loop.hawk-session-token");
+        this.registerWithLoopServer(pushUrl, true);
+
+        return;
+      }
+
+      // No authorization issues, so complete registration.
+      this.onLoopRegistered(error);
+    });
+  },
+
+  /**
+   * Callback from PushHandlerHack - A push notification has been received from
+   * the server.
+   *
+   * @param {String} version The version information from the server.
+   */
+  onHandleNotification: function(version) {
+    if (this.doNotDisturb) {
+      return;
+    }
+
+    this.openChatWindow(null, "LooP", "about:loopconversation#incoming/" + version);
+  },
+
+  /**
+   * Callback from the loopXhr. Checks the registration result.
+   */
+  onLoopRegistered: function(error) {
+    let status = this.loopXhr.response.status;
+    if (status != 200) {
+      // XXX Bubble the precise details up to the UI somehow (bug 1013248).
+      Cu.reportError("Failed to register with the loop server. Code: " +
+        status + " Text: " + this.loopXhr.response.statusText);
+      this._registeredDeferred.reject(status);
+      this._registeredDeferred = null;
+      return;
+    }
+
+    let sessionToken = this.loopXhr.response.headers["hawk-session-token"];
+    if (sessionToken) {
+
+      // XXX should do more validation here
+      if (sessionToken.length === 64) {
+
+        Services.prefs.setCharPref("loop.hawk-session-token", sessionToken);
+      } else {
+        // XXX Bubble the precise details up to the UI somehow (bug 1013248).
+        console.warn("Loop server sent an invalid session token");
+        this._registeredDeferred.reject("session-token-wrong-size");
+        this._registeredDeferred = null;
+        return;
+      }
+    }
+
+    // If we made it this far, we registered just fine.
+    this.registeredLoopServer = true;
+    this._registeredDeferred.resolve();
+    // No need to clear the promise here, everything was good, so we don't need
+    // to re-register.
+  },
+
+  /**
+   * A getter to obtain and store the strings for loop. This is structured
+   * for use by l10n.js.
+   *
+   * @returns {Object} a map of element ids with attributes to set.
+   */
+  get localizedStrings() {
+    if (this._localizedStrings)
+      return this._localizedStrings;
+
+    var stringBundle =
+      Services.strings.createBundle('chrome://browser/locale/loop/loop.properties');
+
+    var map = {};
+    var enumerator = stringBundle.getSimpleEnumeration();
+    while (enumerator.hasMoreElements()) {
+      var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
+
+      // 'textContent' is the default attribute to set if none are specified.
+      var key = string.key, property = 'textContent';
+      var i = key.lastIndexOf('.');
+      if (i >= 0) {
+        property = key.substring(i + 1);
+        key = key.substring(0, i);
+      }
+      if (!(key in map))
+        map[key] = {};
+      map[key][property] = string.value;
+    }
+
+    return this._localizedStrings = map;
+  },
+
+  /**
+   * Opens the chat window
+   *
+   * @param {Object} contentWindow The window to open the chat window in, may
+   *                               be null.
+   * @param {String} title The title of the chat window.
+   * @param {String} url The page to load in the chat window.
+   * @param {String} mode May be "minimized" or undefined.
+   */
+  openChatWindow: function(contentWindow, title, url, mode) {
+    // So I guess the origin is the loop server!?
+    let origin = this.loopServerUri;
+    url = url.spec || url;
+
+    let callback = chatbox => {
+      // We need to use DOMContentLoaded as otherwise the injection will happen
+      // in about:blank and then get lost.
+      // Sadly we can't use chatbox.promiseChatLoaded() as promise chaining
+      // involves event loop spins, which means it might be too late.
+      // Have we already done it?
+      if (chatbox.contentWindow.navigator.mozLoop) {
+        return;
+      }
+
+      chatbox.addEventListener("DOMContentLoaded", function loaded(event) {
+        if (event.target != chatbox.contentDocument) {
+          return;
+        }
+        chatbox.removeEventListener("DOMContentLoaded", loaded, true);
+        injectLoopAPI(chatbox.contentWindow);
+      }, true);
+    };
+
+    Chat.open(contentWindow, origin, title, url, undefined, undefined, callback);
+  }
+};
+
+/**
+ * Public API
+ */
+this.MozLoopService = {
+  /**
+   * Initialized the loop service, and starts registration with the
+   * push and loop servers.
+   */
+  initialize: function() {
+    // If expiresTime is in the future then kick-off registration.
+    if (MozLoopServiceInternal.urlExpiryTimeIsInFuture()) {
+      this._startInitializeTimer();
+    }
+  },
+
+  /**
+   * Internal function, exposed for testing purposes only. Used to start the
+   * initialize timer.
+   */
+  _startInitializeTimer: function() {
+    // Kick off the push notification service into registering after a timeout
+    // this ensures we're not doing too much straight after the browser's finished
+    // starting up.
+    this._initializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    this._initializeTimer.initWithCallback(function() {
+      this.register();
+      this._initializeTimer = null;
+    }.bind(this),
+    MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
+  /**
+   * Starts registration of Loop with the push server, and then will register
+   * with the Loop server. It will return early if already registered.
+   *
+   * @returns {Promise} a promise that is resolved with no params on completion, or
+   *          rejected with an error code or string.
+   */
+  register: function() {
+    return MozLoopServiceInternal.promiseRegisteredWithServers();
+  },
+
+  /**
+   * Used to note a call url expiry time. If the time is later than the current
+   * latest expiry time, then the stored expiry time is increased. For times
+   * sooner, this function is a no-op; this ensures we always have the latest
+   * expiry time for a url.
+   *
+   * This is used to deterimine whether or not we should be registering with the
+   * push server on start.
+   *
+   * @param {Integer} expiryTimeSeconds The seconds since epoch of the expiry time
+   *                                    of the url.
+   */
+  noteCallUrlExpiry: function(expiryTimeSeconds) {
+    MozLoopServiceInternal.expiryTimeSeconds = expiryTimeSeconds;
+  },
+
+  /**
+   * Returns the strings for the specified element. Designed for use
+   * with l10n.js.
+   *
+   * @param {key} The element id to get strings for.
+   * @return {String} A JSON string containing the localized
+   *                  attribute/value pairs for the element.
+   */
+  getStrings: function(key) {
+      var stringData = MozLoopServiceInternal.localizedStrings;
+      if (!(key in stringData)) {
+        Cu.reportError('No string for key: ' + key + 'found');
+        return "";
+      }
+
+      return JSON.stringify(stringData[key]);
+  },
+
+  /**
+   * Retrieves MozLoopService "do not disturb" value.
+   *
+   * @return {Boolean}
+   */
+  get doNotDisturb() {
+    return MozLoopServiceInternal.doNotDisturb;
+  },
+
+  /**
+   * Sets MozLoopService "do not disturb" value.
+   *
+   * @param {Boolean} aFlag
+   */
+  set doNotDisturb(aFlag) {
+    MozLoopServiceInternal.doNotDisturb = aFlag;
+  },
+
+  /**
+   * Returns the current locale
+   *
+   * @return {String} The code of the current locale.
+   */
+  get locale() {
+    try {
+      return Services.prefs.getComplexValue("general.useragent.locale",
+        Ci.nsISupportsString).data;
+    } catch (ex) {
+      return "en-US";
+    }
+  },
+
+  /**
+   * Return any preference under "loop." that's coercible to a character
+   * preference.
+   *
+   * @param {String} prefName The name of the pref without the preceding
+   * "loop."
+   *
+   * Any errors thrown by the Mozilla pref API are logged to the console
+   * and cause null to be returned. This includes the case of the preference
+   * not being found.
+   *
+   * @return {String} on success, null on error
+   */
+  getLoopCharPref: function(prefName) {
+    try {
+      return Services.prefs.getCharPref("loop." + prefName);
+    } catch (ex) {
+      console.log("getLoopCharPref had trouble getting " + prefName +
+        "; exception: " + ex);
+      return null;
+    }
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/README.txt
@@ -0,0 +1,8 @@
+This is the directory for the Loop desktop implementation and the standalone client.
+
+The desktop implementation is the UX built into Firefox, activated by the Loop button on the toolbar. The standalone client is the link-clicker UX for any modern browser that supports WebRTC.
+
+The standalone client is a set of web pages intended to be hosted on a standalone server referenced by the loop-server.
+
+The standalone client exists in standalone/ but shares items (from content/shared/) with the desktop implementation. See the README.md file in the standalone/ directory for how to run the server locally.
+
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/conversation.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/.  -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Conversation</title>
+    <link rel="stylesheet" type="text/css" href="loop/shared/css/common.css">
+    <link rel="stylesheet" type="text/css" href="loop/shared/css/conversation.css">
+ </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 type="text/javascript" src="loop/shared/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/libs/sjcl-dev20140604.js"></script>
+    <script type="text/javascript" src="loop/shared/libs/token.js"></script>
+    <script type="text/javascript" src="loop/shared/libs/hawk-browser-2.2.1.js"></script>
+
+    <script type="text/javascript" src="loop/shared/js/client.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>
+    <script type="text/javascript" src="loop/js/desktopRouter.js"></script>
+    <script type="text/javascript" src="loop/js/conversation.js"></script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/js/conversation.js
@@ -0,0 +1,190 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.conversation = (function(OT, mozL10n) {
+  "use strict";
+
+  var sharedViews = loop.shared.views,
+      // aliasing translation function as __ for concision
+      __ = mozL10n.get;
+
+  /**
+   * App router.
+   * @type {loop.desktopRouter.DesktopConversationRouter}
+   */
+  var router;
+
+  /**
+   * Incoming call view.
+   * @type {loop.shared.views.BaseView}
+   */
+  var IncomingCallView = sharedViews.BaseView.extend({
+    template: _.template([
+      '<h2 data-l10n-id="incoming_call"></h2>',
+      '<p>',
+      '  <button class="btn btn-success btn-accept"',
+      '           data-l10n-id="accept_button"></button>',
+      '  <button class="btn btn-error btn-decline"',
+      '           data-l10n-id="decline_button"></button>',
+      '</p>'
+    ].join("")),
+
+    className: "incoming-call",
+
+    events: {
+      "click .btn-accept": "handleAccept",
+      "click .btn-decline": "handleDecline"
+    },
+
+    /**
+     * User clicked on the "accept" button.
+     * @param  {MouseEvent} event
+     */
+    handleAccept: function(event) {
+      event.preventDefault();
+      this.model.trigger("accept");
+    },
+
+    /**
+     * User clicked on the "decline" button.
+     * @param  {MouseEvent} event
+     */
+    handleDecline: function(event) {
+      event.preventDefault();
+      // XXX For now, we just close the window.
+      window.close();
+    }
+  });
+
+  /**
+   * Call ended view.
+   * @type {loop.shared.views.BaseView}
+   */
+  var EndedCallView = sharedViews.BaseView.extend({
+    template: _.template([
+      '<p>',
+      '  <button class="btn btn-info" data-l10n-id="close_window"></button>',
+      '</p>'
+    ].join("")),
+
+    className: "call-ended",
+
+    events: {
+      "click button": "closeWindow"
+    },
+
+    closeWindow: function(event) {
+      event.preventDefault();
+      // XXX For now, we just close the window.
+      window.close();
+    }
+  });
+
+  /**
+   * Conversation router.
+   *
+   * Required options:
+   * - {loop.shared.models.ConversationModel} conversation Conversation model.
+   * - {loop.shared.components.Notifier}      notifier     Notifier component.
+   *
+   * @type {loop.shared.router.BaseConversationRouter}
+   */
+  var ConversationRouter = loop.desktopRouter.DesktopConversationRouter.extend({
+    routes: {
+      "incoming/:version": "incoming",
+      "call/accept": "accept",
+      "call/ongoing": "conversation",
+      "call/ended": "ended"
+    },
+
+    /**
+     * @override {loop.shared.router.BaseConversationRouter.startCall}
+     */
+    startCall: function() {
+      this.navigate("call/ongoing", {trigger: true});
+    },
+
+    /**
+     * @override {loop.shared.router.BaseConversationRouter.endCall}
+     */
+    endCall: function() {
+      this.navigate("call/ended", {trigger: true});
+    },
+
+    /**
+     * Incoming call route.
+     *
+     * @param {String} loopVersion The version from the push notification, set
+     *                             by the router from the URL.
+     */
+    incoming: function(loopVersion) {
+      this._conversation.set({loopVersion: loopVersion});
+      this._conversation.once("accept", function() {
+        this.navigate("call/accept", {trigger: true});
+      }.bind(this));
+      this.loadView(new IncomingCallView({model: this._conversation}));
+    },
+
+    /**
+     * Accepts an incoming call.
+     */
+    accept: function() {
+      this._conversation.initiate({
+        baseServerUrl: window.navigator.mozLoop.serverUrl,
+        outgoing: false
+      });
+    },
+
+    /**
+     * conversation is the route when the conversation is active. The start
+     * route should be navigated to first.
+     */
+    conversation: function() {
+      if (!this._conversation.isSessionReady()) {
+        console.error("Error: navigated to conversation route without " +
+          "the start route to initialise the call first");
+        this._notifier.errorL10n("cannot_start_call_session_not_ready");
+        return;
+      }
+
+      this.loadView(
+        new loop.shared.views.ConversationView({
+          sdk: OT,
+          model: this._conversation
+      }));
+    },
+
+    /**
+     * XXX: load a view with a close button for now?
+     */
+    ended: function() {
+      this.loadView(new EndedCallView());
+    }
+  });
+
+  /**
+   * Panel initialisation.
+   */
+  function init() {
+    // Do the initial L10n setup, we do this before anything
+    // else to ensure the L10n environment is setup correctly.
+    mozL10n.initialize(window.navigator.mozLoop);
+
+    router = new ConversationRouter({
+      conversation: new loop.shared.models.ConversationModel({}, {sdk: OT}),
+      notifier: new sharedViews.NotificationListView({el: "#messages"})
+    });
+    Backbone.history.start();
+  }
+
+  return {
+    ConversationRouter: ConversationRouter,
+    EndedCallView: EndedCallView,
+    IncomingCallView: IncomingCallView,
+    init: init
+  };
+})(window.OT, document.mozL10n);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/js/desktopRouter.js
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.desktopRouter = (function() {
+  "use strict";
+
+  /**
+   * On the desktop app, the use of about: uris prevents us from changing the
+   * url of the location. As a result, we change the navigate function to simply
+   * activate the new routes, and not try changing the url.
+   *
+   * XXX It is conceivable we might be able to remove this in future, if we
+   * can either swap to resource uris or remove the limitation on the about uris.
+   */
+  var extendedRouter = {
+    navigate: function(to) {
+      this[this.routes[to]]();
+    }
+  };
+
+  var DesktopRouter = loop.shared.router.BaseRouter.extend(extendedRouter);
+
+  var DesktopConversationRouter =
+    loop.shared.router.BaseConversationRouter.extend(extendedRouter);
+
+  return {
+    DesktopRouter: DesktopRouter,
+    DesktopConversationRouter: DesktopConversationRouter
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/js/panel.js
@@ -0,0 +1,248 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.panel = (function(_, mozL10n) {
+  "use strict";
+
+  var sharedViews = loop.shared.views,
+      // aliasing translation function as __ for concision
+      __ = mozL10n.get;
+
+  /**
+   * Panel router.
+   * @type {loop.desktopRouter.DesktopRouter}
+   */
+  var router;
+
+  /**
+   * Do not disturb panel subview.
+   */
+  var DoNotDisturbView = sharedViews.BaseView.extend({
+    template: _.template([
+      '<label>',
+      '  <input type="checkbox" <%- checked %>>',
+      '  <span data-l10n-id="do_not_disturb"></span>',
+      '</label>',
+    ].join('')),
+
+    events: {
+      "click input[type=checkbox]": "toggle"
+    },
+
+    /**
+     * Toggles mozLoop activation status.
+     */
+    toggle: function() {
+      navigator.mozLoop.doNotDisturb = !navigator.mozLoop.doNotDisturb;
+      this.render();
+    },
+
+    render: function() {
+      this.$el.html(this.template({
+        checked: navigator.mozLoop.doNotDisturb ? "checked" : ""
+      }));
+      return this;
+    }
+  });
+
+  /**
+   * Panel view.
+   */
+  var PanelView = sharedViews.BaseView.extend({
+    template: _.template([
+      '<div class="description">',
+      '  <p data-l10n-id="get_link_to_share"></p>',
+      '</div>',
+      '<div class="action">',
+      '  <form class="invite">',
+      '    <input type="text" name="caller" data-l10n-id="caller" required>',
+      '    <button type="submit" class="get-url btn btn-success"',
+      '       data-l10n-id="get_a_call_url"></button>',
+      '  </form>',
+      '  <p class="result hide">',
+      '    <input id="call-url" type="url" readonly>',
+      '    <a class="go-back btn btn-info" href="" data-l10n-id="new_url"></a>',
+      '  </p>',
+      '  <p class="dnd"></p>',
+      '</div>',
+    ].join("")),
+
+    className: "share generate-url",
+
+    /**
+     * Do not disturb view.
+     * @type {DoNotDisturbView|undefined}
+     */
+    dndView: undefined,
+
+    events: {
+      "keyup input[name=caller]": "changeButtonState",
+      "submit form.invite": "getCallUrl",
+      "click a.go-back": "goBack"
+    },
+
+    initialize: function(options) {
+      options = options || {};
+      if (!options.notifier) {
+        throw new Error("missing required notifier");
+      }
+      this.notifier = options.notifier;
+      this.client = new loop.shared.Client({
+        baseServerUrl: navigator.mozLoop.serverUrl
+      });
+    },
+
+    getNickname: function() {
+      return this.$("input[name=caller]").val();
+    },
+
+    getCallUrl: function(event) {
+      this.notifier.clear();
+      event.preventDefault();
+      var callback = function(err, callUrlData) {
+        this.clearPending();
+        if (err) {
+          this.notifier.errorL10n("unable_retrieve_url");
+          this.render();
+          return;
+        }
+        this.onCallUrlReceived(callUrlData);
+      }.bind(this);
+
+      this.setPending();
+      this.client.requestCallUrl(this.getNickname(), callback);
+    },
+
+    goBack: function(event) {
+      event.preventDefault();
+      this.$(".action .result").hide();
+      this.$(".action .invite").show();
+      this.$(".description p").text(__("get_link_to_share"));
+      this.changeButtonState();
+    },
+
+    onCallUrlReceived: function(callUrlData) {
+      this.notifier.clear();
+      this.$(".action .invite").hide();
+      this.$(".action .invite input").val("");
+      this.$(".action .result input").val(callUrlData.call_url);
+      this.$(".action .result").show();
+      this.$(".description p").text(__("share_link_url"));
+    },
+
+    setPending: function() {
+      this.$("[name=caller]").addClass("pending");
+      this.$(".get-url").addClass("disabled").attr("disabled", "disabled");
+    },
+
+    clearPending: function() {
+      this.$("[name=caller]").removeClass("pending");
+      this.changeButtonState();
+    },
+
+    changeButtonState: function() {
+      var enabled = !!this.$("input[name=caller]").val();
+      if (enabled) {
+        this.$(".get-url").removeClass("disabled")
+            .removeAttr("disabled", "disabled");
+      } else {
+        this.$(".get-url").addClass("disabled").attr("disabled", "disabled");
+      }
+    },
+
+    render: function() {
+      this.$el.html(this.template());
+      // Do not Disturb sub view
+      this.dndView = new DoNotDisturbView({el: this.$(".dnd")}).render();
+      return this;
+    }
+  });
+
+  var PanelRouter = loop.desktopRouter.DesktopRouter.extend({
+    /**
+     * DOM document object.
+     * @type {HTMLDocument}
+     */
+    document: undefined,
+
+    routes: {
+      "": "home"
+    },
+
+    initialize: function(options) {
+      options = options || {};
+      if (!options.document) {
+        throw new Error("missing required document");
+      }
+      this.document = options.document;
+
+      this._registerVisibilityChangeEvent();
+
+      this.on("panel:open panel:closed", this.reset, this);
+    },
+
+    /**
+     * Register the DOM visibility API event for the whole document, and trigger
+     * appropriate events accordingly:
+     *
+     * - `panel:opened` when the panel is open
+     * - `panel:closed` when the panel is closed
+     *
+     * @link  http://www.w3.org/TR/page-visibility/
+     */
+    _registerVisibilityChangeEvent: function() {
+      this.document.addEventListener("visibilitychange", function(event) {
+        this.trigger(event.currentTarget.hidden ? "panel:closed"
+                                                : "panel:open");
+      }.bind(this));
+    },
+
+    /**
+     * Default entry point.
+     */
+    home: function() {
+      this.reset();
+    },
+
+    /**
+     * Resets this router to its initial state.
+     */
+    reset: function() {
+      // purge pending notifications
+      this._notifier.clear();
+      // reset home view
+      this.loadView(new PanelView({notifier: this._notifier}));
+    }
+  });
+
+  /**
+   * Panel initialisation.
+   */
+  function init() {
+    // Do the initial L10n setup, we do this before anything
+    // else to ensure the L10n environment is setup correctly.
+    mozL10n.initialize(navigator.mozLoop);
+
+    router = new PanelRouter({
+      document: document,
+      notifier: new sharedViews.NotificationListView({el: "#messages"})
+    });
+    Backbone.history.start();
+
+    // Notify the window that we've finished initalization and initial layout
+    var evtObject = document.createEvent('Event');
+    evtObject.initEvent('loopPanelInitialized', true, false);
+    window.dispatchEvent(evtObject);
+  }
+
+  return {
+    init: init,
+    PanelView: PanelView,
+    DoNotDisturbView: DoNotDisturbView,
+    PanelRouter: PanelRouter
+  };
+})(_, document.mozL10n);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/libs/l10n.js
@@ -0,0 +1,119 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
+// This is a modified version of l10n.js that the pdf.js extension uses.
+// It uses an explicitly passed object for the strings/locale functionality,
+// and does not automatically translate on DOMContentLoaded, but requires
+// initialize to be called. This improves testability and helps to avoid race
+// conditions.
+(function(window) {
+  var gL10nDetails;
+  var gLanguage = '';
+
+  // fetch an l10n objects
+  function getL10nData(key) {
+    var response = gL10nDetails.getStrings(key);
+    var data = JSON.parse(response);
+    if (!data)
+      console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']');
+    return data;
+  }
+
+  // replace {{arguments}} with their values
+  function substArguments(text, args) {
+    if (!args)
+      return text;
+
+    return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) {
+      return name in args ? args[name] : '{{' + name + '}}';
+    });
+  }
+
+  // translate a string
+  function translateString(key, args, fallback) {
+    var data = getL10nData(key);
+    if (!data && fallback)
+      data = {textContent: fallback};
+    if (!data)
+      return '{{' + key + '}}';
+    return substArguments(data.textContent, args);
+  }
+
+  // translate an HTML element
+  function translateElement(element) {
+    if (!element || !element.dataset)
+      return;
+
+    // get the related l10n object
+    var key = element.dataset.l10nId;
+    var data = getL10nData(key);
+    if (!data)
+      return;
+
+    // get arguments (if any)
+    // TODO: more flexible parser?
+    var args;
+    if (element.dataset.l10nArgs) try {
+      args = JSON.parse(element.dataset.l10nArgs);
+    } catch (e) {
+      console.warn('[l10n] could not parse arguments for #' + key + '');
+    }
+
+    // translate element
+    // TODO: security check?
+    for (var k in data)
+      element[k] = substArguments(data[k], args);
+  }
+
+
+  // translate an HTML subtree
+  function translateFragment(element) {
+    element = element || document.querySelector('html');
+
+    // check all translatable children (= w/ a `data-l10n-id' attribute)
+    var children = element.querySelectorAll('*[data-l10n-id]');
+    var elementCount = children.length;
+    for (var i = 0; i < elementCount; i++)
+      translateElement(children[i]);
+
+    // translate element itself if necessary
+    if (element.dataset.l10nId)
+      translateElement(element);
+  }
+
+  // Public API
+  document.mozL10n = {
+    /**
+     * Called to do the initial translation, this should be called
+     * when DOMContentLoaded is fired, or the equivalent time.
+     *
+     * @param {Object} l10nDetails An object implementing the locale attribute
+     *                             and getStrings(key) function.
+     */
+    initialize: function(l10nDetails) {
+      gL10nDetails = l10nDetails;
+      gLanguage = gL10nDetails.locale;
+
+      translateFragment();
+    },
+
+    // get a localized string
+    get: translateString,
+
+    // get the document language
+    getLanguage: function() { return gLanguage; },
+
+    // get the direction (ltr|rtl) of the current language
+    getDirection: function() {
+      // http://www.w3.org/International/questions/qa-scripts
+      // Arabic, Hebrew, Farsi, Pashto, Urdu
+      var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
+      return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
+    },
+
+    // translate an element or document fragment
+    translate: translateFragment
+  };
+})(this);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/panel.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/.  -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Loop Panel</title>
+    <link rel="stylesheet" type="text/css" href="loop/shared/css/common.css">
+    <link rel="stylesheet" type="text/css" href="loop/shared/css/panel.css">
+  </head>
+  <body class="panel" onload="loop.panel.init();">
+
+    <div id="messages"></div>
+
+    <div id="main"></div>
+
+    <script type="text/javascript" src="loop/libs/l10n.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/libs/sjcl-dev20140604.js"></script>
+    <script type="text/javascript" src="loop/shared/libs/token.js"></script>
+    <script type="text/javascript" src="loop/shared/libs/hawk-browser-2.2.1.js"></script>
+
+    <script type="text/javascript" src="loop/shared/js/client.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>
+    <script type="text/javascript" src="loop/js/desktopRouter.js"></script>
+    <script type="text/javascript" src="loop/js/panel.js"></script>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/README.md
@@ -0,0 +1,12 @@
+Loop Shared Web Assets
+======================
+
+This directory contains web assets shared across the Loop client webapp and the
+Loop Firefox Component.
+
+Warning
+-------
+
+Any modification in these files will have possible side effects on both the
+Firefox component and the webapp. The `css/readme.html` file uses all the shared
+styles, you should use it as a way of checking for visual regressions.
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/css/common.css
@@ -0,0 +1,148 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Generic rules */
+
+/**
+ * "Fixes" the Box Model.
+ * @see http://www.paulirish.com/2012/box-sizing-border-box-ftw/
+ */
+*, *:before, *:after {
+  box-sizing: border-box;
+}
+
+body {
+  margin: 0;
+  padding: 0;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans;
+  font-size: 14px;
+  background: #f2f2f2;
+}
+
+button {
+  font-size: .9em; /* for some reason, text is larger within <button> */
+}
+
+img {
+  border: none;
+}
+
+/* Helpers */
+
+/**
+ * Clearfix impl. for modern browsers
+ * 1. The space content is one way to avoid an Opera bug when the
+ *    contenteditable attribute is included anywhere else in the document.
+ *    Otherwise it causes space to appear at the top and bottom of elements
+ *    that are clearfixed.
+ * 2. The use of `table` rather than `block` is only necessary if using
+ *    `:before` to contain the top-margins of child elements.
+ */
+.cf:before,
+.cf:after {
+  content: " ";   /* 1 */
+  display: table; /* 2 */
+}
+
+.cf:after {
+  clear: both;
+}
+
+.hide {
+  display: none;
+}
+
+.tc {
+  text-align: center;
+}
+
+/* Buttons */
+
+.btn {
+  display: inline-block;
+  background: #a5a;
+  border: none;
+  color: #fff;
+  text-decoration: none;
+  padding: .25em .5em .3em;
+  border-radius: .2em;
+}
+
+.btn-info {
+  background: #428BCA;
+}
+
+.btn-success {
+  background: #5cb85c;
+}
+
+.btn-warning {
+  background: #f0ad4e;
+}
+
+.btn-error {
+  background: #d9534f;
+}
+
+.disabled, button[disabled] {
+    cursor: not-allowed;
+    pointer-events: none;
+    opacity: 0.65;
+}
+
+/* Alerts */
+.alert {
+  background: #eee;
+  padding: .2em 1em;
+  margin-bottom: 1em;
+}
+
+.alert p.message {
+  padding: 0;
+  margin: 0;
+}
+
+.alert.alert-error {
+  background: #f99;
+  border: 1px solid #f77;
+}
+
+.alert.alert-warning {
+  background: #fcf8e3;
+  border: 1px solid #fbeed5;
+}
+
+.alert .close {
+  position: relative;
+  top: -.2em;
+  right: -1em;
+}
+
+/* Misc */
+
+.close {
+  float: right;
+  font-size: 20px;
+  font-weight: bold;
+  line-height: 1em;
+  color: #000;
+  opacity: .2;
+}
+
+.close:before {
+  /* \2716 is unicode representation of the close button icon */
+  content: '\2716';
+}
+
+button.close {
+  background: none;
+  border: none;
+  cursor: pointer;
+}
+
+/* Transitions */
+.fade-out {
+  transition: opacity 0.5s ease-in;
+  opacity: 0;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -0,0 +1,73 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Conversation window styles */
+
+.conversation .controls {
+  background: #f2f2f2;
+  padding: .5em;
+}
+
+.conversation .media video {
+  background: #eee;
+}
+
+/* Nested video elements */
+
+.conversation .media.nested {
+  position: relative;
+}
+
+.conversation .media.nested .remote {
+  width: 100%;
+}
+
+.conversation .media.nested .local {
+  position: absolute;
+  bottom: .8em;
+  right: .8em;
+  width: 30%;
+  max-width: 140px;
+}
+
+/* Side by side video elements */
+
+.conversation .media.side-by-side .remote {
+  width: 50%;
+  float: left;
+}
+
+.conversation .media.side-by-side .local {
+  width: 50%;
+}
+
+/**
+ * Overriden SDK styles; .OT_video-container is using absolute positioning
+ * therefore moves the video elements it contains outside of the current
+ * viewport.
+ */
+.conversation .OT_video-container {
+  position: inherit;
+}
+
+/* Call ended view */
+.call-ended p {
+  text-align: center;
+}
+
+/* Incoming call */
+.incoming-call {
+  text-align: center;
+  min-height: 200px;
+}
+
+.incoming-call h2 {
+  font-size: 1.5em;
+  font-weight: normal;
+  margin-top: 3em;
+}
+
+.incoming-call button {
+  margin-right: .2em;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/css/panel.css
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Panel styles */
+
+.panel {
+  /* XXX the Social API panel behaves weirdly on inner element size changes,
+     adding unwanted scrollbars; quickfix is to hide these for now. */
+  overflow: hidden;
+}
+
+.spacer {
+  margin-bottom: 1em;
+}
+
+.share {
+  background: #f2f2f2;
+}
+
+.share .description {
+  background: #f7f7f7 url("../img/icon_32.png") no-repeat 1em 1.5em;
+  border-bottom: 1px solid #c3c3c3;
+  padding: 1em 1em 0 4em;
+}
+
+.share .description .field {
+  padding-bottom: 1em;
+  border-bottom: 1px dotted #ddd;
+}
+
+.share .description select {
+  float: right;
+}
+
+.share .description .preview video {
+  background: #ccc;
+  float: right;
+  width: 180px;
+}
+
+.share .action {
+  clear: right;
+  padding: 1em;
+  border-top: 1px solid #fafafa;
+}
+
+.share .action p {
+  margin: 0 0 1em 0;
+}
+
+.share .action p.dnd {
+  margin-top: 1em;
+}
+
+.share .action input[type="text"],
+.share .action input[type="url"] {
+  border: 1px solid #ccc; /* Overriding background style for a text input (see
+                             below) resets its borders to a weird beveled style;
+                             defining a default 1px border solves the issue. */
+  font-size: .9em;
+  width: 65%;
+  padding: .5em;
+}
+
+.share .action input.pending {
+  background-image: url(../img/loading-icon.gif);
+  background-repeat: no-repeat;
+  background-position: right;
+}
+
+/* For some reason, buttons have a bigger default font size in FF; we're
+   reducing a bit for graphical consistency here. */
+.share .action button {
+  font-size: .9em;
+  padding-top: 6px;
+}
+
+/* Specific cases */
+
+.panel #messages .alert {
+  margin-bottom: 0;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/css/readme.html
@@ -0,0 +1,187 @@
+<!DOCTYPE html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/.  -->
+
+<!-- This file is intended to help frontend developers to easily identify what
+     are the available styles for the Loop UI components. -->
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Loop UI shared CSS information/demo</title>
+  <link type="text/css" rel="stylesheet" href="common.css">
+  <link type="text/css" rel="stylesheet" href="panel.css">
+  <link type="text/css" rel="stylesheet" href="conversation.css">
+  <style>
+    body {
+      width: 600px;
+      margin: 1em auto;
+      background: #fff;
+      font-family: Helvetica, Arial, sans;
+    }
+  </style>
+</head>
+<body>
+  <h1>Loop UI toolkit</h1>
+
+  <h2>Logo icons</h2>
+
+  <p>
+    <img src="../img/icon_32.png"> 32x32 transparent PNG
+    <img src="../img/icon_64.png"> 64x64 transparent PNG
+  </p>
+
+  <p><em><strong>Note:</strong> these are temporary.</em></p>
+
+  <h2>Share panel</h2>
+
+  <h3>Simple</h3>
+
+  <div class="share">
+    <form class="description">
+      <p>This is a simple message.</p>
+    </form>
+    <div class="action">
+      <p><input type="url" value="http://loop.im/plop75"></p>
+      <p>Your name will appear as <a href="">Unnamed</a>.</p>
+    </div>
+  </div>
+
+  <h3>Featuring options</h3>
+
+  <div class="share">
+    <form class="description">
+      <p class="field">
+        <label>Share this link with a friend to
+          <select>
+            <option>browse together</option>
+            <option selected="selected">video chat</option>
+            <option>audio chat</option>
+            <option>text chat</option>
+          </select>
+        </label>
+      </p>
+      <p class="field">
+        <label>
+          Use webcam <select><option>Foo</option></select>
+        </label>
+      </p>
+      <p class="field">
+        <label>Use whatever
+          <select><option>Long foo is long indeed</option></select>
+        </label>
+      </p>
+      <p class="preview cf">
+        Preview <video></video>
+      </p>
+    </form>
+    <div class="action">
+      <p><input type="url" value="http://loop.im/plop75"></p>
+      <p>Your name will appear as <a href="">Unnamed</a>.</p>
+    </div>
+  </div>
+
+  <h2>Conversation window</h2>
+
+  <p><em>The conversation component adapts automatically to its container to
+    occupy all the available space.</em></p>
+
+  <h3>Large</h3>
+
+  <div class="conversation">
+    <div class="media nested">
+      <video class="remote"></video>
+      <video class="local"></video>
+    </div>
+  </div>
+
+  <h3>Large with controls</h3>
+
+  <div class="conversation">
+    <nav class="controls">
+      <button class="btn">Start</button>
+      <button class="btn">Stop</button>
+    </nav>
+    <div class="media nested">
+      <video class="remote"></video>
+      <video class="local"></video>
+    </div>
+  </div>
+
+  <h3>Small (think chat window)</h3>
+
+  <div style="width: 204px">
+    <div class="conversation">
+      <div class="media nested">
+        <video class="remote"></video>
+        <video class="local"></video>
+      </div>
+    </div>
+  </div>
+
+  <h3>Side by side</h3>
+
+  <div class="conversation">
+    <div class="media side-by-side">
+      <video class="remote"></video>
+      <video class="local"></video>
+    </div>
+  </div>
+
+  <h2>Buttons</h2>
+
+  <h3>Using <code>&lt;a&gt;</code></h3>
+
+  <p>
+    <a href="" class="btn">default</a>
+    <a href="" class="btn btn-info">info</a>
+    <a href="" class="btn btn-success">success</a>
+    <a href="" class="btn btn-warning">warning</a>
+    <a href="" class="btn btn-error">error</a>
+  </p>
+
+  <h3>Inline</h3>
+
+  <p>Click <a href="" class="btn btn-info">here</a>.</p>
+
+  <h3>Using <code>&lt;button&gt;</code></h3>
+
+  <p>
+    <button class="btn">default</button>
+    <button class="btn btn-info">info</button>
+    <button class="btn btn-success">success</button>
+    <button class="btn btn-warning">warning</button>
+    <button class="btn btn-error">error</button>
+  </p>
+
+  <h2>Alerts</h2>
+
+  <div class="alert alert-error">
+    <button class="close"></button>
+    <p class="message">Oops! Something went really wrong.</p>
+  </div>
+
+  <div class="alert alert-warning">
+    <button class="close"></button>
+    <p class="message">Oops! This is a warning.</p>
+  </div>
+
+  <h2>Incoming call</h2>
+
+  <div class="incoming-call">
+    <h2>Incoming call</h2>
+    <p>
+      <button class="btn btn-success btn-accept">Accept</button>
+      <button class="btn btn-error btn-decline">Decline</button>
+    </p>
+  </div>
+
+  <script>
+  window.onload = function() {
+    [].forEach.call(document.querySelectorAll("video"), function(video) {
+      video.setAttribute("src", "http://v2v.cc/~j/theora_testsuite/320x240.ogg");
+    });
+  };
+  </script>
+</body>
+</html>
new file mode 100644
index 0000000000000000000000000000000000000000..03cc4d461f83d29d4c842d9cc2172f2c310197f7
GIT binary patch
literal 2351
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
new file mode 100644
index 0000000000000000000000000000000000000000..8368d7c5cd9818703ad4293c2e2f13441f452b4d
GIT binary patch
literal 4081
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
a`{00wsCAFAd%@7pOSqY_CA!EE$NWF|gfg1|
new file mode 100644
index 0000000000000000000000000000000000000000..1c72ebb554be018511ae972c3f2361dff02dce02
GIT binary patch
literal 2545
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
B8LI#Q
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/js/client.js
@@ -0,0 +1,362 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true, hawk, deriveHawkCredentials */
+
+var loop = loop || {};
+loop.shared = loop.shared || {};
+loop.shared.Client = (function($) {
+  "use strict";
+
+  /**
+   * Loop server client.
+   *
+   * @param {Object} settings Settings object.
+   */
+  function Client(settings) {
+    settings = settings || {};
+    if (!settings.hasOwnProperty("baseServerUrl") ||
+        !settings.baseServerUrl) {
+      throw new Error("missing required baseServerUrl");
+    }
+
+    // allowing an |in| test rather than a more type || allows us to dependency
+    // inject a non-existent mozLoop
+    if ("mozLoop" in settings) {
+      this.mozLoop = settings.mozLoop;
+    } else {
+      this.mozLoop = navigator.mozLoop;
+    }
+
+    this.settings = settings;
+  }
+
+  Client.prototype = {
+    /**
+     * Converts from hours to seconds
+     */
+    _hoursToSeconds: function(value) {
+      return value * 60 * 60;
+    },
+
+    /**
+     * Validates a data object to confirm it has the specified properties.
+     *
+     * @param  {Object} The data object to verify
+     * @param  {Array} The list of properties to verify within the object
+     * @return This returns either the specific property if only one
+     *         property is specified, or it returns all properties
+     */
+    _validate: function(data, properties) {
+      if (typeof data !== "object") {
+        throw new Error("Invalid data received from server");
+      }
+
+      properties.forEach(function (property) {
+        if (!data.hasOwnProperty(property)) {
+          throw new Error("Invalid data received from server - missing " +
+            property);
+        }
+      });
+
+      if (properties.length <= 1) {
+        return data[properties[0]];
+      }
+
+      return data;
+    },
+
+    /**
+     * Generic handler for XHR failures.
+     *
+     * @param {Function} cb Callback(err)
+     * @param jqXHR See jQuery docs
+     * @param textStatus See jQuery docs
+     * @param errorThrown See jQuery docs
+     */
+    _failureHandler: function(cb, jqXHR, textStatus, errorThrown) {
+      var error = "Unknown error.",
+          jsonRes = jqXHR && jqXHR.responseJSON || {};
+      // Received error response format:
+      // { "status": "errors",
+      //   "errors": [{
+      //      "location": "url",
+      //      "name": "token",
+      //      "description": "invalid token"
+      // }]}
+      if (jsonRes.status === "errors" && Array.isArray(jsonRes.errors)) {
+        error = "Details: " + jsonRes.errors.map(function(err) {
+          return Object.keys(err).map(function(field) {
+            return field + ": " + err[field];
+          }).join(", ");
+        }).join("; ");
+      }
+      var message = "HTTP " + jqXHR.status + " " + errorThrown +
+          "; " + error;
+      console.error(message);
+      cb(new Error(message));
+    },
+
+    /**
+     * Ensures the client is registered with the push server.
+     *
+     * Callback parameters:
+     * - err null on successful registration, non-null otherwise.
+     *
+     * @param {Function} cb Callback(err)
+     */
+    _ensureRegistered: function(cb) {
+      navigator.mozLoop.ensureRegistered(function(err) {
+        cb(err);
+      }.bind(this));
+    },
+
+    /**
+     * Ensures that the client picks up the hawk-session-token
+     * put in preferences by the LoopService registration code,
+     * derives hawk credentials from them, and saves them in
+     * this._credentials.
+     *
+     * @param {Function} cb Callback(err)
+     *  if err is set to null in the callback, that indicates that the
+     *  credentials have been successfully attached to this object.
+     *
+     * @private
+     *
+     * @note That as currently written, this is only ever expected to be called
+     * from browser UI code (ie it relies on mozLoop).
+     */
+    _ensureCredentials: function(cb) {
+      if (this._credentials) {
+        cb(null);
+        return;
+      }
+
+      var hawkSessionToken =
+        this.mozLoop.getLoopCharPref("hawk-session-token");
+      if (!hawkSessionToken) {
+        var msg = "loop.hawk-session-token pref not found";
+        console.warn(msg);
+        cb(new Error(msg));
+        return;
+      }
+
+      // XXX do we want to use any of the other hawk params (eg to track clock
+      // skew, etc)?
+      var serverDerivedKeyLengthInBytes = 2 * 32;
+      deriveHawkCredentials(hawkSessionToken, "sessionToken",
+        serverDerivedKeyLengthInBytes, function (hawkCredentials) {
+          this._credentials = hawkCredentials;
+          cb(null);
+        }.bind(this));
+    },
+
+    /**
+     * Internal handler for requesting a call url from the server.
+     *
+     * Callback parameters:
+     * - err null on successful registration, non-null otherwise.
+     * - callUrlData an object of the obtained call url data if successful:
+     * -- call_url: The url of the call
+     * -- expiresAt: The amount of hours until expiry of the url
+     *
+     * @param  {String} simplepushUrl a registered Simple Push URL
+     * @param  {string} nickname the nickname of the future caller
+     * @param  {Function} cb Callback(err, callUrlData)
+     */
+    _requestCallUrlInternal: function(nickname, cb) {
+      var endpoint = this.settings.baseServerUrl + "/call-url/",
+          reqData  = {callerId: nickname};
+
+      var req = $.ajax({
+        type: "POST",
+        url: endpoint,
+        data: reqData,
+        xhrFields: {
+          withCredentials: false
+        },
+        crossDomain: true,
+        beforeSend: function (xhr, settings) {
+          try {
+            this._attachAnyServerCreds(xhr, settings);
+          } catch (ex) {
+            cb(ex);
+            return false;
+          }
+          return true;
+        }.bind(this),
+        success: function(callUrlData) {
+          // XXX split this out into two functions for better readability
+          try {
+            cb(null, this._validate(callUrlData, ["call_url", "expiresAt"]));
+
+            var expiresHours = this._hoursToSeconds(callUrlData.expiresAt);
+            navigator.mozLoop.noteCallUrlExpiry(expiresHours);
+          } catch (err) {
+            console.log("Error requesting call info", err);
+            cb(err);
+          }
+        }.bind(this),
+        dataType: "json"
+      });
+
+      req.fail(this._failureHandler.bind(this, cb));
+    },
+
+    /**
+     * Requests a call URL from the Loop server. It will note the
+     * expiry time for the url with the mozLoop api.
+     *
+     * Callback parameters:
+     * - err null on successful registration, non-null otherwise.
+     * - callUrlData an object of the obtained call url data if successful:
+     * -- call_url: The url of the call
+     * -- expiresAt: The amount of hours until expiry of the url
+     *
+     * @param  {String} simplepushUrl a registered Simple Push URL
+     * @param  {string} nickname the nickname of the future caller
+     * @param  {Function} cb Callback(err, callUrlData)
+     */
+    requestCallUrl: function(nickname, cb) {
+      this._ensureRegistered(function(err) {
+        if (err) {
+          console.log("Error registering with Loop server, code: " + err);
+          cb(err);
+          return;
+        }
+        this._ensureCredentials(function (err) {
+          if (err) {
+            console.log("Error setting up credentials: " + err);
+            cb(err);
+            return;
+          }
+          this._requestCallUrlInternal(nickname, cb);
+        }.bind(this));
+      }.bind(this));
+    },
+
+    /**
+     * Requests call information from the server for all calls since the
+     * given version.
+     *
+     * @param  {String} version the version identifier from the push
+     *                          notification
+     * @param  {Function} cb Callback(err, calls)
+     */
+    requestCallsInfo: function(version, cb) {
+      this._ensureCredentials(function (err) {
+        if (err) {
+          console.log("Error setting up credentials: " + err);
+          cb(err);
+          return;
+        }
+        this._requestCallsInfoInternal(version, cb);
+      }.bind(this));
+    },
+
+    _requestCallsInfoInternal: function(version, cb) {
+      if (!version) {
+        throw new Error("missing required parameter version");
+      }
+
+      var endpoint = this.settings.baseServerUrl + "/calls";
+
+      // XXX It is likely that we'll want to move some of this to whatever
+      // opens the chat window, but we'll need to decide that once we make a
+      // decision on chrome versus content, and know if we're going with
+      // LoopService or a frameworker.
+      var req = $.ajax({
+        type: "GET",
+        url: endpoint + "?version=" + version,
+        xhrFields: {
+          withCredentials: false
+        },
+        crossDomain: true,
+        beforeSend: function (xhr, settings) {
+          try {
+            this._attachAnyServerCreds(xhr, settings);
+          } catch (ex) {
+            cb(ex);
+            return false;
+          }
+          return true;
+        }.bind(this),
+        success: function(callsData) {
+          try {
+            cb(null, this._validate(callsData, ["calls"]));
+          } catch (err) {
+            console.log("Error requesting calls info", err);
+            cb(err);
+          }
+        }.bind(this),
+        dataType: "json"
+      });
+
+      req.fail(this._failureHandler.bind(this, cb));
+    },
+
+    /**
+     * Posts a call request to the server for a call represented by the
+     * loopToken. Will return the session data for the call.
+     *
+     * @param  {String} loopToken The loopToken representing the call
+     * @param  {Function} cb Callback(err, sessionData)
+     */
+    requestCallInfo: function(loopToken, cb) {
+      if (!loopToken) {
+        throw new Error("missing required parameter loopToken");
+      }
+
+      var req = $.ajax({
+        url:         this.settings.baseServerUrl + "/calls/" + loopToken,
+        method:      "POST",
+        contentType: "application/json",
+        data:        JSON.stringify({}),
+        dataType:    "json"
+      });
+
+      req.done(function(sessionData) {
+        try {
+          cb(null, this._validate(sessionData, [
+            "sessionId", "sessionToken", "apiKey"
+          ]));
+        } catch (err) {
+          console.log("Error requesting call info", err);
+          cb(err);
+        }
+      }.bind(this));
+
+      req.fail(this._failureHandler.bind(this, cb));
+    },
+
+    /**
+     * If this._credentials is set, adds a hawk Authorization header based
+     * based on those credentials to the passed-in XHR.
+     *
+     * @param xhr        request to add any header to
+     * @param settings   settings object passed to jQuery.ajax()
+     * @private
+     */
+    _attachAnyServerCreds: function(xhr, settings) {
+      // if the server needs credentials and didn't get them, it will
+      // return failure for us, so if we don't have any creds, don't try to
+      // attach them.
+      if (!this._credentials) {
+        return;
+      }
+
+      var header = hawk.client.header(settings.url, settings.type,
+        { credentials: this._credentials });
+      if (header.err) {
+        throw new Error(header.err);
+      }
+
+      xhr.setRequestHeader("Authorization", header.field);
+
+      return;
+    }
+  };
+
+  return Client;
+})(jQuery);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/js/models.js
@@ -0,0 +1,241 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.shared = loop.shared || {};
+loop.shared.models = (function() {
+  "use strict";
+
+  /**
+   * Conversation model.
+   */
+  var ConversationModel = Backbone.Model.extend({
+    defaults: {
+      ongoing:      false,     // Ongoing call flag
+      callerId:     undefined, // Loop caller id
+      loopToken:    undefined, // Loop conversation token
+      loopVersion:  undefined, // Loop version for /calls/ information. This
+                               // is the version received from the push
+                               // notification and is used by the server to
+                               // determine the pending calls
+      sessionId:    undefined, // OT session id
+      sessionToken: undefined, // OT session token
+      apiKey:       undefined  // OT api key
+    },
+
+    /**
+     * SDK object.
+     * @type {OT}
+     */
+    sdk: undefined,
+
+    /**
+     * SDK session object.
+     * @type {XXX}
+     */
+    session: undefined,
+
+    /**
+     * Constructor.
+     *
+     * Required options:
+     * - {OT} sdk: SDK object.
+     *
+     * @param  {Object} attributes Attributes object.
+     * @param  {Object} options    Options object.
+     */
+    initialize: function(attributes, options) {
+      options = options || {};
+      if (!options.sdk) {
+        throw new Error("missing required sdk");
+      }
+      this.sdk = options.sdk;
+    },
+
+    /**
+     * Initiates a conversation, requesting call session information to the Loop
+     * server and updates appropriately the current model attributes with the
+     * data.
+     *
+     * Available options:
+     *
+     * - {String} baseServerUrl The server URL
+     * - {Boolean} outgoing Set to true if this model represents the
+     *                            outgoing call.
+     *
+     * Triggered events:
+     *
+     * - `session:ready` when the session information have been successfully
+     *   retrieved from the server;
+     * - `session:error` when the request failed.
+     *
+     * @param {Object} options Options object
+     */
+    initiate: function(options) {
+      var client = new loop.shared.Client({
+        baseServerUrl: options.baseServerUrl
+      });
+
+      function handleResult(err, sessionData) {
+        /*jshint validthis:true */
+        if (err) {
+          this.trigger("session:error", new Error(
+            "Retrieval of session information failed: HTTP " + err));
+          return;
+        }
+
+        // XXX For incoming calls we might have more than one call queued.
+        // For now, we'll just assume the first call is the right information.
+        // We'll probably really want to be getting this data from the
+        // background worker on the desktop client.
+        // Bug 990714 should fix this.
+        if (!options.outgoing)
+          sessionData = sessionData[0];
+
+        this.setReady(sessionData);
+      }
+
+      if (options.outgoing) {
+        client.requestCallInfo(this.get("loopToken"), handleResult.bind(this));
+      }
+      else {
+        client.requestCallsInfo(this.get("loopVersion"),
+          handleResult.bind(this));
+      }
+    },
+
+    /**
+     * Checks that the session is ready.
+     *
+     * @return {Boolean}
+     */
+    isSessionReady: function() {
+      return !!this.get("sessionId");
+    },
+
+    /**
+     * Sets session information and triggers the `session:ready` event.
+     *
+     * @param {Object} sessionData Conversation session information.
+     */
+    setReady: function(sessionData) {
+      // Explicit property assignment to prevent later "surprises"
+      this.set({
+        sessionId:    sessionData.sessionId,
+        sessionToken: sessionData.sessionToken,
+        apiKey:       sessionData.apiKey
+      }).trigger("session:ready", this);
+      return this;
+    },
+
+    /**
+     * Starts a SDK session and subscribe to call events.
+     */
+    startSession: function() {
+      if (!this.isSessionReady()) {
+        throw new Error("Can't start session as it's not ready");
+      }
+      this.session = this.sdk.initSession(this.get("sessionId"));
+      this.listenTo(this.session, "sessionConnected", this._sessionConnected);
+      this.listenTo(this.session, "streamCreated", this._streamCreated);
+      this.listenTo(this.session, "connectionDestroyed",
+                                  this._connectionDestroyed);
+      this.listenTo(this.session, "sessionDisconnected",
+                                  this._sessionDisconnected);
+      this.listenTo(this.session, "networkDisconnected",
+                                  this._networkDisconnected);
+      this.session.connect(this.get("apiKey"), this.get("sessionToken"));
+    },
+
+    /**
+     * Ends current session.
+     */
+    endSession: function() {
+      this.session.disconnect();
+      this.once("session:ended", this.stopListening, this);
+      this.set("ongoing", false);
+    },
+
+    /**
+     * Session is created.
+     * http://tokbox.com/opentok/libraries/client/js/reference/SessionConnectEvent.html
+     *
+     * @param  {SessionConnectEvent} event
+     */
+    _sessionConnected: function(event) {
+      this.trigger("session:connected", event);
+      this.set("ongoing", true);
+    },
+
+    /**
+     * New created streams are available.
+     * http://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
+     *
+     * @param  {StreamEvent} event
+     */
+    _streamCreated: function(event) {
+      this.trigger("session:stream-created", event);
+    },
+
+    /**
+     * Local user hung up.
+     * http://tokbox.com/opentok/libraries/client/js/reference/SessionDisconnectEvent.html
+     *
+     * @param  {SessionDisconnectEvent} event
+     */
+    _sessionDisconnected: function(event) {
+      this.trigger("session:ended");
+      this.set("ongoing", false);
+    },
+
+    /**
+     * Peer hung up. Disconnects local session.
+     * http://tokbox.com/opentok/libraries/client/js/reference/ConnectionEvent.html
+     *
+     * @param  {ConnectionEvent} event
+     */
+    _connectionDestroyed: function(event) {
+      this.trigger("session:peer-hungup", {
+        connectionId: event.connection.connectionId
+      });
+      this.endSession();
+    },
+
+    /**
+     * Network was disconnected.
+     * http://tokbox.com/opentok/libraries/client/js/reference/ConnectionEvent.html
+     *
+     * @param {ConnectionEvent} event
+     */
+    _networkDisconnected: function(event) {
+      this.trigger("session:network-disconnected");
+      this.endSession();
+    },
+  });
+
+  /**
+   * Notification model.
+   */
+  var NotificationModel = Backbone.Model.extend({
+    defaults: {
+      level: "info",
+      message: ""
+    }
+  });
+
+  /**
+   * Notification collection
+   */
+  var NotificationCollection = Backbone.Collection.extend({
+    model: NotificationModel
+  });
+
+  return {
+    ConversationModel: ConversationModel,
+    NotificationCollection: NotificationCollection,
+    NotificationModel: NotificationModel
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/js/router.js
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.shared = loop.shared || {};
+loop.shared.router = (function(l10n) {
+  "use strict";
+
+  /**
+   * Base Router. Allows defining a main active view and ease toggling it when
+   * the active route changes.
+   *
+   * @link http://mikeygee.com/blog/backbone.html
+   */
+  var BaseRouter = Backbone.Router.extend({
+    /**
+     * Active view.
+     * @type {loop.shared.views.BaseView}
+     */
+    _activeView: undefined,
+
+    /**
+     * Notifications dispatcher.
+     * @type {loop.shared.views.NotificationListView}
+     */
+    _notifier: undefined,
+
+    /**
+     * Constructor.
+     *
+     * Required options:
+     * - {loop.shared.views.NotificationListView} notifier Notifier view.
+     *
+     * @param  {Object} options Options object.
+     */
+    constructor: function(options) {
+      options = options || {};
+      if (!options.notifier) {
+        throw new Error("missing required notifier");
+      }
+      this._notifier = options.notifier;
+
+      Backbone.Router.apply(this, arguments);
+    },
+
+    /**
+     * Loads and render current active view.
+     *
+     * @param {loop.shared.views.BaseView} view View.
+     */
+    loadView : function(view) {
+      if (this._activeView) {
+        this._activeView.remove();
+      }
+      this._activeView = view.render().show();
+      this.updateView(this._activeView.$el);
+    },
+
+    /**
+     * Updates main div element with provided contents.
+     *
+     * @param  {jQuery} $el Element.
+     */
+    updateView: function($el) {
+      $("#main").html($el);
+    }
+  });
+
+  /**
+   * Base conversation router, implementing common behaviors when handling
+   * a conversation.
+   */
+  var BaseConversationRouter = BaseRouter.extend({
+    /**
+     * Current conversation.
+     * @type {loop.shared.models.ConversationModel}
+     */
+    _conversation: undefined,
+
+    /**
+     * Constructor. Defining it as `constructor` allows implementing an
+     * `initialize` method in child classes without needing calling this parent
+     * one. See http://backbonejs.org/#Model-constructor (same for Router)
+     *
+     * Required options:
+     * - {loop.shared.model.ConversationModel}    model    Conversation model.
+     *
+     * @param {Object} options Options object.
+     */
+    constructor: function(options) {
+      options = options || {};
+      if (!options.conversation) {
+        throw new Error("missing required conversation");
+      }
+      this._conversation = options.conversation;
+
+      this.listenTo(this._conversation, "session:ready", this._onSessionReady);
+      this.listenTo(this._conversation, "session:ended", this._onSessionEnded);
+      this.listenTo(this._conversation, "session:peer-hungup",
+                                        this._onPeerHungup);
+      this.listenTo(this._conversation, "session:network-disconnected",
+                                        this._onNetworkDisconnected);
+
+      BaseRouter.apply(this, arguments);
+    },
+
+    /**
+     * Starts the call. This method should be overriden.
+     */
+    startCall: function() {},
+
+    /**
+     * Ends the call. This method should be overriden.
+     */
+    endCall: function() {},
+
+    /**
+     * Session is ready.
+     */
+    _onSessionReady: function() {
+      this.startCall();
+    },
+
+    /**
+     * Session has ended. Notifies the user and ends the call.
+     */
+    _onSessionEnded: function() {
+      this._notifier.warnL10n("call_has_ended");
+      this.endCall();
+    },
+
+    /**
+     * Peer hung up. Notifies the user and ends the call.
+     *
+     * Event properties:
+     * - {String} connectionId: OT session id
+     *
+     * @param {Object} event
+     */
+    _onPeerHungup: function() {
+      this._notifier.warnL10n("peer_ended_conversation");
+      this.endCall();
+    },
+
+    /**
+     * Network disconnected. Notifies the user and ends the call.
+     */
+    _onNetworkDisconnected: function() {
+      this._notifier.warnL10n("network_disconnected");
+      this.endCall();
+    }
+  });
+
+  return {
+    BaseRouter: BaseRouter,
+    BaseConversationRouter: BaseConversationRouter
+  };
+})(document.webL10n || document.mozL10n);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/js/views.js
@@ -0,0 +1,386 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global loop:true */
+
+var loop = loop || {};
+loop.shared = loop.shared || {};
+loop.shared.views = (function(_, OT, l10n) {
+  "use strict";
+
+  var sharedModels = loop.shared.models;
+
+  /**
+   * L10n view. Translates resulting view DOM fragment once rendered.
+   */
+  var L10nView = (function() {
+    var L10nViewImpl   = Backbone.View.extend(), // Original View constructor
+        originalExtend = L10nViewImpl.extend;    // Original static extend fn
+
+    /**
+     * Patches View extend() method so we can hook and patch any declared render
+     * method.
+     *
+     * @return {Backbone.View} Extended view with patched render() method.
+     */
+    L10nViewImpl.extend = function() {
+      var ExtendedView   = originalExtend.apply(this, arguments),
+          originalRender = ExtendedView.prototype.render;
+
+      /**
+       * Wraps original render() method to translate contents once they're
+       * rendered.
+       *
+       * @return {Backbone.View} Extended view instance.
+       */
+      ExtendedView.prototype.render = function() {
+        if (originalRender) {
+          originalRender.apply(this, arguments);
+          l10n.translate(this.el);
+        }
+        return this;
+      };
+
+      return ExtendedView;
+    };
+
+    return L10nViewImpl;
+  })();
+
+  /**
+   * Base view.
+   */
+  var BaseView = L10nView.extend({
+    /**
+     * Hides view element.
+     *
+     * @return {BaseView}
+     */
+    hide: function() {
+      this.$el.hide();
+      return this;
+    },
+
+    /**
+     * Shows view element.
+     *
+     * @return {BaseView}
+     */
+    show: function() {
+      this.$el.show();
+      return this;
+    },
+
+    /**
+     * Base render implementation: renders an attached template if available.
+     *
+     * Note: You need to override this if you want to do fancier stuff, eg.
+     *       rendering the template using model data.
+     *
+     * @return {BaseView}
+     */
+    render: function() {
+      if (this.template) {
+        this.$el.html(this.template());
+      }
+      return this;
+    }
+  });
+
+  /**
+   * Conversation view.
+   */
+  var ConversationView = BaseView.extend({
+    className: "conversation",
+
+    template: _.template([
+      '<nav class="controls">',
+      '  <button class="btn stop" data-l10n-id="stop"></button>',
+      '</nav>',
+      '<div class="media nested">',
+      // Both these wrappers are required by the SDK; this is fragile and
+      // will break if a future version of the SDK updates this generated DOM,
+      // especially as the SDK seems to actually move wrapped contents into
+      // their own generated stuff.
+      '  <div class="remote"><div class="incoming"></div></div>',
+      '  <div class="local"><div class="outgoing"></div></div>',
+      '</div>'
+    ].join("")),
+
+    // height set to "auto" to fix video layout on Google Chrome
+    // @see https://bugzilla.mozilla.org/show_bug.cgi?id=991122
+    videoStyles: {
+      width: "100%",
+      height: "auto",
+      style: { "bugDisplayMode": "off" }
+    },
+
+    events: {
+      'click .btn.stop': 'hangup'
+    },
+
+    /**
+     * Establishes webrtc communication using OT sdk.
+     */
+    initialize: function(options) {
+      options = options || {};
+      if (!options.sdk) {
+        throw new Error("missing required sdk");
+      }
+      this.sdk = options.sdk;
+
+      this.listenTo(this.model, "session:connected", this.publish);
+      this.listenTo(this.model, "session:stream-created", this._streamCreated);
+      this.listenTo(this.model, ["session:peer-hungup",
+                                 "session:network-disconnected",
+                                 "session:ended"].join(" "), this.unpublish);
+      this.model.startSession();
+    },
+
+    /**
+     * Subscribes and attaches each created stream to a DOM element.
+     *
+     * XXX: for now we only support a single remote stream, hence a single DOM
+     *      element.
+     *
+     * http://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
+     *
+     * @param  {StreamEvent} event
+     */
+    _streamCreated: function(event) {
+      var incoming = this.$(".incoming").get(0);
+      event.streams.forEach(function(stream) {
+        if (stream.connection.connectionId !==
+            this.model.session.connection.connectionId) {
+          this.model.session.subscribe(stream, incoming, this.videoStyles);
+        }
+      }.bind(this));
+    },
+
+    /**
+     * Hangs up current conversation.
+     *
+     * @param  {MouseEvent} event
+     */
+    hangup: function(event) {
+      event.preventDefault();
+      this.unpublish();
+      this.model.endSession();
+    },
+
+    /**
+     * Publishes remote streams available once a session is connected.
+     *
+     * http://tokbox.com/opentok/libraries/client/js/reference/SessionConnectEvent.html
+     *
+     * @param  {SessionConnectEvent} event
+     */
+    publish: function(event) {
+      var outgoing = this.$(".outgoing").get(0);
+
+      this.publisher = this.sdk.initPublisher(outgoing, this.videoStyles);
+
+      // Suppress OT GuM custom dialog, see bug 1018875
+      function preventOpeningAccessDialog(event) {
+        event.preventDefault();
+      }
+      this.publisher.on("accessDialogOpened", preventOpeningAccessDialog);
+      this.publisher.on("accessDenied", preventOpeningAccessDialog);
+
+      this.model.session.publish(this.publisher);
+    },
+
+    /**
+     * Unpublishes local stream.
+     */
+    unpublish: function() {
+      // Unregister access OT GuM custom dialog listeners, see bug 1018875
+      this.publisher.off("accessDialogOpened");
+      this.publisher.off("accessDenied");
+
+      this.model.session.unpublish(this.publisher);
+    },
+
+    /**
+     * Renders this view.
+     *
+     * @return {ConversationView}
+     */
+    render: function() {
+      this.$el.html(this.template(this.model.toJSON()));
+      return this;
+    }
+  });
+
+  /**
+   * Notification view.
+   */
+  var NotificationView = BaseView.extend({
+    template: _.template([
+      '<div class="alert alert-<%- level %>">',
+      '  <button class="close"></button>',
+      '  <p class="message"><%- message %></p>',
+      '</div>'
+    ].join("")),
+
+    events: {
+      "click .close": "dismiss"
+    },
+
+    dismiss: function(event) {
+      event.preventDefault();
+      this.$el.addClass("fade-out");
+      setTimeout(function() {
+        this.collection.remove(this.model);
+        this.remove();
+      }.bind(this), 500); // XXX make timeout value configurable
+    },
+
+    render: function() {
+      this.$el.html(this.template(this.model.toJSON()));
+      return this;
+    }
+  });
+
+  /**
+   * Notification list view.
+   */
+  var NotificationListView = Backbone.View.extend({
+    /**
+     * Constructor.
+     *
+     * Available options:
+     * - {loop.shared.models.NotificationCollection} collection Notifications
+     *                                                          collection
+     *
+     * @param  {Object} options Options object
+     */
+    initialize: function(options) {
+      options = options || {};
+      if (!options.collection) {
+        this.collection = new sharedModels.NotificationCollection();
+      }
+      this.listenTo(this.collection, "reset add remove", this.render);
+    },
+
+    /**
+     * Clears the notification stack.
+     */
+    clear: function() {
+      this.collection.reset();
+    },
+
+    /**
+     * Adds a new notification to the stack, triggering rendering of it.
+     *
+     * @param  {Object|NotificationModel} notification Notification data.
+     */
+    notify: function(notification) {
+      this.collection.add(notification);
+    },
+
+    /**
+     * Adds a new notification to the stack using an l10n message identifier,
+     * triggering rendering of it.
+     *
+     * @param  {String} messageId L10n message id
+     * @param  {String} level     Notification level
+     */
+    notifyL10n: function(messageId, level) {
+      this.notify({
+        message: l10n.get(messageId),
+        level: level
+      });
+    },
+
+    /**
+     * Adds a warning notification to the stack and renders it.
+     *
+     * @return {String} message
+     */
+    warn: function(message) {
+      this.notify({level: "warning", message: message});
+    },
+
+    /**
+     * Adds a l10n warning notification to the stack and renders it.
+     *
+     * @param  {String} messageId L10n message id
+     */
+    warnL10n: function(messageId) {
+      this.warn(l10n.get(messageId));
+    },
+
+    /**
+     * Adds an error notification to the stack and renders it.
+     *
+     * @return {String} message
+     */
+    error: function(message) {
+      this.notify({level: "error", message: message});
+    },
+
+    /**
+     * Adds a l10n rror notification to the stack and renders it.
+     *
+     * @param  {String} messageId L10n message id
+     */
+    errorL10n: function(messageId) {
+      this.error(l10n.get(messageId));
+    },
+
+    /**
+     * Renders this view.
+     *
+     * @return {loop.shared.views.NotificationListView}
+     */
+    render: function() {
+      this.$el.html(this.collection.map(function(notification) {
+        return new NotificationView({
+          model: notification,
+          collection: this.collection
+        }).render().$el;
+      }.bind(this)));
+      return this;
+    }
+  });
+
+  /**
+   * Unsupported Browsers view.
+   */
+  var UnsupportedBrowserView = BaseView.extend({
+    template: _.template([
+      '<div>',
+      '  <h2 data-l10n-id="incompatible_browser"></h2>',
+      '  <p data-l10n-id="powered_by_webrtc"></p>',
+      '  <p data-l10n-id="use_latest_firefox" ',
+      '    data-l10n-args=\'{"ff_url": "https://www.mozilla.org/firefox/"}\'>',
+      '  </p>',
+      '</div>'
+    ].join(""))
+  });
+
+  /**
+   * Unsupported Browsers view.
+   */
+  var UnsupportedDeviceView = BaseView.extend({
+    template: _.template([
+      '<div>',
+      '  <h2 data-l10n-id="incompatible_device"></h2>',
+      '  <p data-l10n-id="sorry_device_unsupported"></p>',
+      '  <p data-l10n-id="use_firefox_windows_mac_linux"></p>',
+      '</div>'
+    ].join(""))
+  });
+
+  return {
+    L10nView: L10nView,
+    BaseView: BaseView,
+    ConversationView: ConversationView,
+    NotificationListView: NotificationListView,
+    NotificationView: NotificationView,
+    UnsupportedBrowserView: UnsupportedBrowserView,
+    UnsupportedDeviceView: UnsupportedDeviceView
+  };
+})(_, window.OT, document.webL10n || document.mozL10n);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/backbone-1.1.2.js
@@ -0,0 +1,9 @@
+//     Backbone.js 1.1.2
+
+//     (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Backbone may be freely distributed under the MIT license.
+//     For all details and documentation:
+//     http://backbonejs.org
+
+(function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h<u;h++){t=o[h];if(a=this._events[t]){this._events[t]=s=[];if(e||r){for(l=0,f=a.length;l<f;l++){n=a[l];if(e&&e!==n.callback&&e!==n.callback._callback||r&&r!==n.context){s.push(n)}}}if(!s.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=o.call(arguments,1);if(!c(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)f(i,e);if(r)f(r,arguments);return this},stopListening:function(t,e,r){var s=this._listeningTo;if(!s)return this;var n=!e&&!r;if(!r&&typeof e==="object")r=this;if(t)(s={})[t._listenId]=t;for(var a in s){t=s[a];t.off(e,r,this);if(n||i.isEmpty(t._events))delete this._listeningTo[a]}return this}};var l=/\s+/;var c=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(l.test(i)){var n=i.split(l);for(var a=0,o=n.length;a<o;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var f=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,o);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e);return}};var d={listenTo:"on",listenToOnce:"once"};i.each(d,function(t,e){u[e]=function(e,r,s){var n=this._listeningTo||(this._listeningTo={});var a=e._listenId||(e._listenId=i.uniqueId("l"));n[a]=e;if(!s&&typeof r==="object")s=this;e[t](r,s,this);return this}});u.bind=u.on;u.unbind=u.off;i.extend(e,u);var p=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId("c");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,"defaults"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(p.prototype,u,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,r){var s,n,a,o,h,u,l,c;if(t==null)return this;if(typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;a=r.unset;h=r.silent;o=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=i.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in n)this.id=n[this.idAttribute];for(s in n){e=n[s];if(!i.isEqual(c[s],e))o.push(s);if(!i.isEqual(l[s],e)){this.changed[s]=e}else{delete this.changed[s]}a?delete c[s]:c[s]=e}if(!h){if(o.length)this._pending=r;for(var f=0,d=o.length;f<d;f++){this.trigger("change:"+o[f],this,c[o[f]],r)}}if(u)return this;if(!h){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e,r=false;var s=this._changing?this._previousAttributes:this.attributes;for(var n in t){if(i.isEqual(s[n],e=t[n]))continue;(r||(r={}))[n]=e}return r},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var r=t.success;t.success=function(i){if(!e.set(e.parse(i,t),t))return false;if(r)r(e,i,t);e.trigger("sync",e,i,t)};q(this,t);return this.sync("read",this,t)},save:function(t,e,r){var s,n,a,o=this.attributes;if(t==null||typeof t==="object"){s=t;r=e}else{(s={})[t]=e}r=i.extend({validate:true},r);if(s&&!r.wait){if(!this.set(s,r))return false}else{if(!this._validate(s,r))return false}if(s&&r.wait){this.attributes=i.extend({},o,s)}if(r.parse===void 0)r.parse=true;var h=this;var u=r.success;r.success=function(t){h.attributes=o;var e=h.parse(t,r);if(r.wait)e=i.extend(s||{},e);if(i.isObject(e)&&!h.set(e,r)){return false}if(u)u(h,t,r);h.trigger("sync",h,t,r)};q(this,r);n=this.isNew()?"create":r.patch?"patch":"update";if(n==="patch")r.attrs=s;a=this.sync(n,this,r);if(s&&r.wait)this.attributes=o;return a},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var s=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(t.wait||e.isNew())s();if(r)r(e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};if(this.isNew()){t.success();return false}q(this,t);var n=this.sync("delete",this,t);if(!t.wait)s();return n},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||M();if(this.isNew())return t;return t.replace(/([^\/])$/,"$1/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var v=["keys","values","pairs","invert","pick","omit"];i.each(v,function(t){p.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.attributes);return i[t].apply(i,e)}});var g=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,remove:false};i.extend(g.prototype,u,{model:p,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,y))},remove:function(t,e){var r=!i.isArray(t);t=r?[t]:i.clone(t);e||(e={});var s,n,a,o;for(s=0,n=t.length;s<n;s++){o=t[s]=this.get(t[s]);if(!o)continue;delete this._byId[o.id];delete this._byId[o.cid];a=this.indexOf(o);this.models.splice(a,1);this.length--;if(!e.silent){e.index=a;o.trigger("remove",o,this,e)}this._removeReference(o,e)}return r?t[0]:t},set:function(t,e){e=i.defaults({},e,m);if(e.parse)t=this.parse(t,e);var r=!i.isArray(t);t=r?t?[t]:[]:i.clone(t);var s,n,a,o,h,u,l;var c=e.at;var f=this.model;var d=this.comparator&&c==null&&e.sort!==false;var v=i.isString(this.comparator)?this.comparator:null;var g=[],y=[],_={};var b=e.add,w=e.merge,x=e.remove;var E=!d&&b&&x?[]:false;for(s=0,n=t.length;s<n;s++){h=t[s]||{};if(h instanceof p){a=o=h}else{a=h[f.prototype.idAttribute||"id"]}if(u=this.get(a)){if(x)_[u.cid]=true;if(w){h=h===o?o.attributes:h;if(e.parse)h=u.parse(h,e);u.set(h,e);if(d&&!l&&u.hasChanged(v))l=true}t[s]=u}else if(b){o=t[s]=this._prepareModel(h,e);if(!o)continue;g.push(o);this._addReference(o,e)}o=u||o;if(E&&(o.isNew()||!_[o.id]))E.push(o);_[o.id]=true}if(x){for(s=0,n=this.length;s<n;++s){if(!_[(o=this.models[s]).cid])y.push(o)}if(y.length)this.remove(y,e)}if(g.length||E&&E.length){if(d)l=true;this.length+=g.length;if(c!=null){for(s=0,n=g.length;s<n;s++){this.models.splice(c+s,0,g[s])}}else{if(E)this.models.length=0;var k=E||g;for(s=0,n=k.length;s<n;s++){this.models.push(k[s])}}}if(l)this.sort({silent:true});if(!e.silent){for(s=0,n=g.length;s<n;s++){(o=g[s]).trigger("add",o,this,e)}if(l||E&&E.length)this.trigger("sort",this,e)}return r?t[0]:t},reset:function(t,e){e||(e={});for(var r=0,s=this.models.length;r<s;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return o.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t]||this._byId[t.id]||this._byId[t.cid]},at:function(t){return this.models[t]},where:function(t,e){if(i.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(i.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(i.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return i.invoke(this.models,"get",t)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var r=this;t.success=function(i){var s=t.reset?"reset":"set";r[s](i,t);if(e)e(r,i,t);r.trigger("sync",r,i,t)};q(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var r=this;var s=e.success;e.success=function(t,i){if(e.wait)r.add(t,e);if(s)s(t,i,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof p)return t;e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_addReference:function(t,e){this._byId[t.cid]=t;if(t.id!=null)this._byId[t.id]=t;if(!t.collection)t.collection=this;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","difference","indexOf","shuffle","lastIndexOf","isEmpty","chain","sample"];i.each(_,function(t){g.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.models);return i[t].apply(i,e)}});var b=["groupBy","countBy","sortBy","indexBy"];i.each(b,function(t){g.prototype[t]=function(e,r){var s=i.isFunction(e)?e:function(t){return t.get(e)};return i[t](this.models,s,r)}});var w=e.View=function(t){this.cid=i.uniqueId("view");t||(t={});i.extend(this,i.pick(t,E));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];i.extend(w.prototype,u,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,i){if(this.$el)this.undelegateEvents();this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0];if(i!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=i.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[t[e]];if(!r)continue;var s=e.match(x);var n=s[1],a=s[2];r=i.bind(r,this);n+=".delegateEvents"+this.cid;if(a===""){this.$el.on(n,r)}else{this.$el.on(n,a,r)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");var r=e.$("<"+i.result(this,"tagName")+">").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('<iframe src="javascript:0" tabindex="-1">');this.iframe=a.hide().appendTo("body")[0].contentWindow;this.navigate(r)}if(this._hasPushState){e.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!n){e.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=r;var o=this.location;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){this.fragment=this.getFragment(null,true);this.location.replace(this.root+"#"+this.fragment);return true}else if(this._hasPushState&&this.atRoot()&&o.hash){this.fragment=this.getHash().replace(R,"");this.history.replaceState({},document.title,this.root+this.fragment)}}if(!this.options.silent)return this.loadUrl()},stop:function(){e.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return i.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||""));t=t.replace(j,"");if(this.fragment===t)return;this.fragment=t;if(t===""&&i!=="/")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var U=function(t,e){var r=this;var s;if(t&&i.has(t,"constructor")){s=t.constructor}else{s=function(){return r.apply(this,arguments)}}i.extend(s,r,e);var n=function(){this.constructor=s};n.prototype=r.prototype;s.prototype=new n;if(t)i.extend(s.prototype,t);s.__super__=r.prototype;return s};p.extend=g.extend=$.extend=w.extend=N.extend=U;var M=function(){throw new Error('A "url" property or function must be specified')};var q=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}};return e});
+//# sourceMappingURL=backbone-min.map
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/hawk-browser-2.2.1.js
@@ -0,0 +1,556 @@
+/*
+    HTTP Hawk Authentication Scheme
+    Copyright (c) 2012-2014, Eran Hammer <eran@hammer.io>
+    BSD Licensed
+*/
+
+
+// Declare namespace
+
+var hawk = {
+    internals: {}
+};
+
+
+hawk.client = {
+
+    // Generate an Authorization header for a given request
+
+    /*
+        uri: 'http://example.com/resource?a=b' or object generated by hawk.utils.parseUri()
+        method: HTTP verb (e.g. 'GET', 'POST')
+        options: {
+
+            // Required
+
+            credentials: {
+                id: 'dh37fgj492je',
+                key: 'aoijedoaijsdlaksjdl',
+                algorithm: 'sha256'                                 // 'sha1', 'sha256'
+            },
+
+            // Optional
+
+            ext: 'application-specific',                        // Application specific data sent via the ext attribute
+            timestamp: Date.now() / 1000,                       // A pre-calculated timestamp in seconds
+            nonce: '2334f34f',                                  // A pre-generated nonce
+            localtimeOffsetMsec: 400,                           // Time offset to sync with server time (ignored if timestamp provided)
+            payload: '{"some":"payload"}',                      // UTF-8 encoded string for body hash generation (ignored if hash provided)
+            contentType: 'application/json',                    // Payload content-type (ignored if hash provided)
+            hash: 'U4MKKSmiVxk37JCCrAVIjV=',                    // Pre-calculated payload hash
+            app: '24s23423f34dx',                               // Oz application id
+            dlg: '234sz34tww3sd'                                // Oz delegated-by application id
+        }
+    */
+
+    header: function (uri, method, options) {
+
+        var result = {
+            field: '',
+            artifacts: {}
+        };
+
+        // Validate inputs
+
+        if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') ||
+            !method || typeof method !== 'string' ||
+            !options || typeof options !== 'object') {
+
+            result.err = 'Invalid argument type';
+            return result;
+        }
+
+        // Application time
+
+        var timestamp = options.timestamp || hawk.utils.now(options.localtimeOffsetMsec);
+
+        // Validate credentials
+
+        var credentials = options.credentials;
+        if (!credentials ||
+            !credentials.id ||
+            !credentials.key ||
+            !credentials.algorithm) {
+
+            result.err = 'Invalid credentials object';
+            return result;
+        }
+
+        if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            result.err = 'Unknown algorithm';
+            return result;
+        }
+
+        // Parse URI
+
+        if (typeof uri === 'string') {
+            uri = hawk.utils.parseUri(uri);
+        }
+
+        // Calculate signature
+
+        var artifacts = {
+            ts: timestamp,
+            nonce: options.nonce || hawk.utils.randomString(6),
+            method: method,
+            resource: uri.relative,
+            host: uri.hostname,
+            port: uri.port,
+            hash: options.hash,
+            ext: options.ext,
+            app: options.app,
+            dlg: options.dlg
+        };
+
+        result.artifacts = artifacts;
+
+        // Calculate payload hash
+
+        if (!artifacts.hash &&
+            (options.payload || options.payload === '')) {
+
+            artifacts.hash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
+        }
+
+        var mac = hawk.crypto.calculateMac('header', credentials, artifacts);
+
+        // Construct header
+
+        var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== '';       // Other falsey values allowed
+        var header = 'Hawk id="' + credentials.id +
+                     '", ts="' + artifacts.ts +
+                     '", nonce="' + artifacts.nonce +
+                     (artifacts.hash ? '", hash="' + artifacts.hash : '') +
+                     (hasExt ? '", ext="' + hawk.utils.escapeHeaderAttribute(artifacts.ext) : '') +
+                     '", mac="' + mac + '"';
+
+        if (artifacts.app) {
+            header += ', app="' + artifacts.app +
+                      (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"';
+        }
+
+        result.field = header;
+
+        return result;
+    },
+
+
+    // Validate server response
+
+    /*
+        request:    object created via 'new XMLHttpRequest()' after response received
+        artifacts:  object received from header().artifacts
+        options: {
+            payload:    optional payload received
+            required:   specifies if a Server-Authorization header is required. Defaults to 'false'
+        }
+    */
+
+    authenticate: function (request, credentials, artifacts, options) {
+
+        options = options || {};
+
+        var getHeader = function (name) {
+
+            return request.getResponseHeader ? request.getResponseHeader(name) : request.getHeader(name);
+        };
+
+        var wwwAuthenticate = getHeader('www-authenticate');
+        if (wwwAuthenticate) {
+
+            // Parse HTTP WWW-Authenticate header
+
+            var attributes = hawk.utils.parseAuthorizationHeader(wwwAuthenticate, ['ts', 'tsm', 'error']);
+            if (!attributes) {
+                return false;
+            }
+
+            if (attributes.ts) {
+                var tsm = hawk.crypto.calculateTsMac(attributes.ts, credentials);
+                if (tsm !== attributes.tsm) {
+                    return false;
+                }
+
+                hawk.utils.setNtpOffset(attributes.ts - Math.floor((new Date()).getTime() / 1000));     // Keep offset at 1 second precision
+            }
+        }
+
+        // Parse HTTP Server-Authorization header
+
+        var serverAuthorization = getHeader('server-authorization');
+        if (!serverAuthorization &&
+            !options.required) {
+
+            return true;
+        }
+
+        var attributes = hawk.utils.parseAuthorizationHeader(serverAuthorization, ['mac', 'ext', 'hash']);
+        if (!attributes) {
+            return false;
+        }
+
+        var modArtifacts = {
+            ts: artifacts.ts,
+            nonce: artifacts.nonce,
+            method: artifacts.method,
+            resource: artifacts.resource,
+            host: artifacts.host,
+            port: artifacts.port,
+            hash: attributes.hash,
+            ext: attributes.ext,
+            app: artifacts.app,
+            dlg: artifacts.dlg
+        };
+
+        var mac = hawk.crypto.calculateMac('response', credentials, modArtifacts);
+        if (mac !== attributes.mac) {
+            return false;
+        }
+
+        if (!options.payload &&
+            options.payload !== '') {
+
+            return true;
+        }
+
+        if (!attributes.hash) {
+            return false;
+        }
+
+        var calculatedHash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, getHeader('content-type'));
+        return (calculatedHash === attributes.hash);
+    },
+
+    message: function (host, port, message, options) {
+
+        // Validate inputs
+
+        if (!host || typeof host !== 'string' ||
+            !port || typeof port !== 'number' ||
+            message === null || message === undefined || typeof message !== 'string' ||
+            !options || typeof options !== 'object') {
+
+            return null;
+        }
+
+        // Application time
+
+        var timestamp = options.timestamp || hawk.utils.now(options.localtimeOffsetMsec);
+
+        // Validate credentials
+
+        var credentials = options.credentials;
+        if (!credentials ||
+            !credentials.id ||
+            !credentials.key ||
+            !credentials.algorithm) {
+
+            // Invalid credential object
+            return null;
+        }
+
+        if (hawk.crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+            return null;
+        }
+
+        // Calculate signature
+
+        var artifacts = {
+            ts: timestamp,
+            nonce: options.nonce || hawk.utils.randomString(6),
+            host: host,
+            port: port,
+            hash: hawk.crypto.calculatePayloadHash(message, credentials.algorithm)
+        };
+
+        // Construct authorization
+
+        var result = {
+            id: credentials.id,
+            ts: artifacts.ts,
+            nonce: artifacts.nonce,
+            hash: artifacts.hash,
+            mac: hawk.crypto.calculateMac('message', credentials, artifacts)
+        };
+
+        return result;
+    },
+
+    authenticateTimestamp: function (message, credentials, updateClock) {           // updateClock defaults to true
+
+        var tsm = hawk.crypto.calculateTsMac(message.ts, credentials);
+        if (tsm !== message.tsm) {
+            return false;
+        }
+
+        if (updateClock !== false) {
+            hawk.utils.setNtpOffset(message.ts - Math.floor((new Date()).getTime() / 1000));    // Keep offset at 1 second precision
+        }
+
+        return true;
+    }
+};
+
+
+hawk.crypto = {
+
+    headerVersion: '1',
+
+    algorithms: ['sha1', 'sha256'],
+
+    calculateMac: function (type, credentials, options) {
+
+        var normalized = hawk.crypto.generateNormalizedString(type, options);
+
+        var hmac = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()](normalized, credentials.key);
+        return hmac.toString(CryptoJS.enc.Base64);
+    },
+
+    generateNormalizedString: function (type, options) {
+
+        var normalized = 'hawk.' + hawk.crypto.headerVersion + '.' + type + '\n' +
+                         options.ts + '\n' +
+                         options.nonce + '\n' +
+                         (options.method || '').toUpperCase() + '\n' +
+                         (options.resource || '') + '\n' +
+                         options.host.toLowerCase() + '\n' +
+                         options.port + '\n' +
+                         (options.hash || '') + '\n';
+
+        if (options.ext) {
+            normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+        }
+
+        normalized += '\n';
+
+        if (options.app) {
+            normalized += options.app + '\n' +
+                          (options.dlg || '') + '\n';
+        }
+
+        return normalized;
+    },
+
+    calculatePayloadHash: function (payload, algorithm, contentType) {
+
+        var hash = CryptoJS.algo[algorithm.toUpperCase()].create();
+        hash.update('hawk.' + hawk.crypto.headerVersion + '.payload\n');
+        hash.update(hawk.utils.parseContentType(contentType) + '\n');
+        hash.update(payload);
+        hash.update('\n');
+        return hash.finalize().toString(CryptoJS.enc.Base64);
+    },
+
+    calculateTsMac: function (ts, credentials) {
+
+        var hash = CryptoJS['Hmac' + credentials.algorithm.toUpperCase()]('hawk.' + hawk.crypto.headerVersion + '.ts\n' + ts + '\n', credentials.key);
+        return hash.toString(CryptoJS.enc.Base64);
+    }
+};
+
+
+// localStorage compatible interface
+
+hawk.internals.LocalStorage = function () {
+
+    this._cache = {};
+    this.length = 0;
+
+    this.getItem = function (key) {
+
+        return this._cache.hasOwnProperty(key) ? String(this._cache[key]) : null;
+    };
+
+    this.setItem = function (key, value) {
+
+        this._cache[key] = String(value);
+        this.length = Object.keys(this._cache).length;
+    };
+
+    this.removeItem = function (key) {
+
+        delete this._cache[key];
+        this.length = Object.keys(this._cache).length;
+    };
+
+    this.clear = function () {
+
+        this._cache = {};
+        this.length = 0;
+    };
+
+    this.key = function (i) {
+
+        return Object.keys(this._cache)[i || 0];
+    };
+};
+
+
+hawk.utils = {
+
+    storage: new hawk.internals.LocalStorage(),
+
+    setStorage: function (storage) {
+
+        var ntpOffset = hawk.utils.storage.getItem('hawk_ntp_offset');
+        hawk.utils.storage = storage;
+        if (ntpOffset) {
+            hawk.utils.setNtpOffset(ntpOffset);
+        }
+    },
+
+    setNtpOffset: function (offset) {
+
+        try {
+            hawk.utils.storage.setItem('hawk_ntp_offset', offset);
+        }
+        catch (err) {
+            console.error('[hawk] could not write to storage.');
+            console.error(err);
+        }
+    },
+
+    getNtpOffset: function () {
+
+        var offset = hawk.utils.storage.getItem('hawk_ntp_offset');
+        if (!offset) {
+            return 0;
+        }
+
+        return parseInt(offset, 10);
+    },
+
+    now: function (localtimeOffsetMsec) {
+
+        return Math.floor(((new Date()).getTime() + (localtimeOffsetMsec || 0)) / 1000) + hawk.utils.getNtpOffset();
+    },
+
+    escapeHeaderAttribute: function (attribute) {
+
+        return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');
+    },
+
+    parseContentType: function (header) {
+
+        if (!header) {
+            return '';
+        }
+
+        return header.split(';')[0].replace(/^\s+|\s+$/g, '').toLowerCase();
+    },
+
+    parseAuthorizationHeader: function (header, keys) {
+
+        if (!header) {
+            return null;
+        }
+
+        var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/);       // Header: scheme[ something]
+        if (!headerParts) {
+            return null;
+        }
+
+        var scheme = headerParts[1];
+        if (scheme.toLowerCase() !== 'hawk') {
+            return null;
+        }
+
+        var attributesString = headerParts[2];
+        if (!attributesString) {
+            return null;
+        }
+
+        var attributes = {};
+        var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) {
+
+            // Check valid attribute names
+
+            if (keys.indexOf($1) === -1) {
+                return;
+            }
+
+            // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9
+
+            if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+                return;
+            }
+
+            // Check for duplicates
+
+            if (attributes.hasOwnProperty($1)) {
+                return;
+            }
+
+            attributes[$1] = $2;
+            return '';
+        });
+
+        if (verify !== '') {
+            return null;
+        }
+
+        return attributes;
+    },
+
+    randomString: function (size) {
+
+        var randomSource = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+        var len = randomSource.length;
+
+        var result = [];
+        for (var i = 0; i < size; ++i) {
+            result[i] = randomSource[Math.floor(Math.random() * len)];
+        }
+
+        return result.join('');
+    },
+
+    parseUri: function (input) {
+
+        // Based on: parseURI 1.2.2
+        // http://blog.stevenlevithan.com/archives/parseuri
+        // (c) Steven Levithan <stevenlevithan.com>
+        // MIT License
+
+        var keys = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'hostname', 'port', 'resource', 'relative', 'pathname', 'directory', 'file', 'query', 'fragment'];
+
+        var uriRegex = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?)(?:#(.*))?)/;
+        var uriByNumber = input.match(uriRegex);
+        var uri = {};
+
+        for (var i = 0, il = keys.length; i < il; ++i) {
+            uri[keys[i]] = uriByNumber[i] || '';
+        }
+
+        if (uri.port === '') {
+            uri.port = (uri.protocol.toLowerCase() === 'http' ? '80' : (uri.protocol.toLowerCase() === 'https' ? '443' : ''));
+        }
+
+        return uri;
+    }
+};
+
+
+// $lab:coverage:off$
+
+// Based on: Crypto-JS v3.1.2
+// Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
+// http://code.google.com/p/crypto-js/
+// http://code.google.com/p/crypto-js/wiki/License
+
+var CryptoJS = CryptoJS || function (h, r) { var k = {}, l = k.lib = {}, n = function () { }, f = l.Base = { extend: function (a) { n.prototype = this; var b = new n; a && b.mixIn(a); b.hasOwnProperty("init") || (b.init = function () { b.$super.init.apply(this, arguments) }); b.init.prototype = b; b.$super = this; return b }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var b in a) a.hasOwnProperty(b) && (this[b] = a[b]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } }, j = l.WordArray = f.extend({ init: function (a, b) { a = this.words = a || []; this.sigBytes = b != r ? b : 4 * a.length }, toString: function (a) { return (a || s).stringify(this) }, concat: function (a) { var b = this.words, d = a.words, c = this.sigBytes; a = a.sigBytes; this.clamp(); if (c % 4) for (var e = 0; e < a; e++) b[c + e >>> 2] |= (d[e >>> 2] >>> 24 - 8 * (e % 4) & 255) << 24 - 8 * ((c + e) % 4); else if (65535 < d.length) for (e = 0; e < a; e += 4) b[c + e >>> 2] = d[e >>> 2]; else b.push.apply(b, d); this.sigBytes += a; return this }, clamp: function () { var a = this.words, b = this.sigBytes; a[b >>> 2] &= 4294967295 << 32 - 8 * (b % 4); a.length = h.ceil(b / 4) }, clone: function () { var a = f.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var b = [], d = 0; d < a; d += 4) b.push(4294967296 * h.random() | 0); return new j.init(b, a) } }), m = k.enc = {}, s = m.Hex = { stringify: function (a) { var b = a.words; a = a.sigBytes; for (var d = [], c = 0; c < a; c++) { var e = b[c >>> 2] >>> 24 - 8 * (c % 4) & 255; d.push((e >>> 4).toString(16)); d.push((e & 15).toString(16)) } return d.join("") }, parse: function (a) { for (var b = a.length, d = [], c = 0; c < b; c += 2) d[c >>> 3] |= parseInt(a.substr(c, 2), 16) << 24 - 4 * (c % 8); return new j.init(d, b / 2) } }, p = m.Latin1 = { stringify: function (a) { var b = a.words; a = a.sigBytes; for (var d = [], c = 0; c < a; c++) d.push(String.fromCharCode(b[c >>> 2] >>> 24 - 8 * (c % 4) & 255)); return d.join("") }, parse: function (a) { for (var b = a.length, d = [], c = 0; c < b; c++) d[c >>> 2] |= (a.charCodeAt(c) & 255) << 24 - 8 * (c % 4); return new j.init(d, b) } }, t = m.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(p.stringify(a))) } catch (b) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return p.parse(unescape(encodeURIComponent(a))) } }, q = l.BufferedBlockAlgorithm = f.extend({ reset: function () { this._data = new j.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = t.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var b = this._data, d = b.words, c = b.sigBytes, e = this.blockSize, f = c / (4 * e), f = a ? h.ceil(f) : h.max((f | 0) - this._minBufferSize, 0); a = f * e; c = h.min(4 * a, c); if (a) { for (var g = 0; g < a; g += e) this._doProcessBlock(d, g); g = d.splice(0, a); b.sigBytes -= c } return new j.init(g, c) }, clone: function () { var a = f.clone.call(this); a._data = this._data.clone(); return a }, _minBufferSize: 0 }); l.Hasher = q.extend({ cfg: f.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { q.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (b, d) { return (new a.init(d)).finalize(b) } }, _createHmacHelper: function (a) { return function (b, d) { return (new u.HMAC.init(a, d)).finalize(b) } } }); var u = k.algo = {}; return k }(Math);
+(function () { var k = CryptoJS, b = k.lib, m = b.WordArray, l = b.Hasher, d = [], b = k.algo.SHA1 = l.extend({ _doReset: function () { this._hash = new m.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (n, p) { for (var a = this._hash.words, e = a[0], f = a[1], h = a[2], j = a[3], b = a[4], c = 0; 80 > c; c++) { if (16 > c) d[c] = n[p + c] | 0; else { var g = d[c - 3] ^ d[c - 8] ^ d[c - 14] ^ d[c - 16]; d[c] = g << 1 | g >>> 31 } g = (e << 5 | e >>> 27) + b + d[c]; g = 20 > c ? g + ((f & h | ~f & j) + 1518500249) : 40 > c ? g + ((f ^ h ^ j) + 1859775393) : 60 > c ? g + ((f & h | f & j | h & j) - 1894007588) : g + ((f ^ h ^ j) - 899497514); b = j; j = h; h = f << 30 | f >>> 2; f = e; e = g } a[0] = a[0] + e | 0; a[1] = a[1] + f | 0; a[2] = a[2] + h | 0; a[3] = a[3] + j | 0; a[4] = a[4] + b | 0 }, _doFinalize: function () { var b = this._data, d = b.words, a = 8 * this._nDataBytes, e = 8 * b.sigBytes; d[e >>> 5] |= 128 << 24 - e % 32; d[(e + 64 >>> 9 << 4) + 14] = Math.floor(a / 4294967296); d[(e + 64 >>> 9 << 4) + 15] = a; b.sigBytes = 4 * d.length; this._process(); return this._hash }, clone: function () { var b = l.clone.call(this); b._hash = this._hash.clone(); return b } }); k.SHA1 = l._createHelper(b); k.HmacSHA1 = l._createHmacHelper(b) })();
+(function (k) { for (var g = CryptoJS, h = g.lib, v = h.WordArray, j = h.Hasher, h = g.algo, s = [], t = [], u = function (q) { return 4294967296 * (q - (q | 0)) | 0 }, l = 2, b = 0; 64 > b;) { var d; a: { d = l; for (var w = k.sqrt(d), r = 2; r <= w; r++) if (!(d % r)) { d = !1; break a } d = !0 } d && (8 > b && (s[b] = u(k.pow(l, 0.5))), t[b] = u(k.pow(l, 1 / 3)), b++); l++ } var n = [], h = h.SHA256 = j.extend({ _doReset: function () { this._hash = new v.init(s.slice(0)) }, _doProcessBlock: function (q, h) { for (var a = this._hash.words, c = a[0], d = a[1], b = a[2], k = a[3], f = a[4], g = a[5], j = a[6], l = a[7], e = 0; 64 > e; e++) { if (16 > e) n[e] = q[h + e] | 0; else { var m = n[e - 15], p = n[e - 2]; n[e] = ((m << 25 | m >>> 7) ^ (m << 14 | m >>> 18) ^ m >>> 3) + n[e - 7] + ((p << 15 | p >>> 17) ^ (p << 13 | p >>> 19) ^ p >>> 10) + n[e - 16] } m = l + ((f << 26 | f >>> 6) ^ (f << 21 | f >>> 11) ^ (f << 7 | f >>> 25)) + (f & g ^ ~f & j) + t[e] + n[e]; p = ((c << 30 | c >>> 2) ^ (c << 19 | c >>> 13) ^ (c << 10 | c >>> 22)) + (c & d ^ c & b ^ d & b); l = j; j = g; g = f; f = k + m | 0; k = b; b = d; d = c; c = m + p | 0 } a[0] = a[0] + c | 0; a[1] = a[1] + d | 0; a[2] = a[2] + b | 0; a[3] = a[3] + k | 0; a[4] = a[4] + f | 0; a[5] = a[5] + g | 0; a[6] = a[6] + j | 0; a[7] = a[7] + l | 0 }, _doFinalize: function () { var d = this._data, b = d.words, a = 8 * this._nDataBytes, c = 8 * d.sigBytes; b[c >>> 5] |= 128 << 24 - c % 32; b[(c + 64 >>> 9 << 4) + 14] = k.floor(a / 4294967296); b[(c + 64 >>> 9 << 4) + 15] = a; d.sigBytes = 4 * b.length; this._process(); return this._hash }, clone: function () { var b = j.clone.call(this); b._hash = this._hash.clone(); return b } }); g.SHA256 = j._createHelper(h); g.HmacSHA256 = j._createHmacHelper(h) })(Math);
+(function () { var c = CryptoJS, k = c.enc.Utf8; c.algo.HMAC = c.lib.Base.extend({ init: function (a, b) { a = this._hasher = new a.init; "string" == typeof b && (b = k.parse(b)); var c = a.blockSize, e = 4 * c; b.sigBytes > e && (b = a.finalize(b)); b.clamp(); for (var f = this._oKey = b.clone(), g = this._iKey = b.clone(), h = f.words, j = g.words, d = 0; d < c; d++) h[d] ^= 1549556828, j[d] ^= 909522486; f.sigBytes = g.sigBytes = e; this.reset() }, reset: function () { var a = this._hasher; a.reset(); a.update(this._iKey) }, update: function (a) { this._hasher.update(a); return this }, finalize: function (a) { var b = this._hasher; a = b.finalize(a); b.reset(); return b.finalize(this._oKey.clone().concat(a)) } }) })();
+(function () { var h = CryptoJS, j = h.lib.WordArray; h.enc.Base64 = { stringify: function (b) { var e = b.words, f = b.sigBytes, c = this._map; b.clamp(); b = []; for (var a = 0; a < f; a += 3) for (var d = (e[a >>> 2] >>> 24 - 8 * (a % 4) & 255) << 16 | (e[a + 1 >>> 2] >>> 24 - 8 * ((a + 1) % 4) & 255) << 8 | e[a + 2 >>> 2] >>> 24 - 8 * ((a + 2) % 4) & 255, g = 0; 4 > g && a + 0.75 * g < f; g++) b.push(c.charAt(d >>> 6 * (3 - g) & 63)); if (e = c.charAt(64)) for (; b.length % 4;) b.push(e); return b.join("") }, parse: function (b) { var e = b.length, f = this._map, c = f.charAt(64); c && (c = b.indexOf(c), -1 != c && (e = c)); for (var c = [], a = 0, d = 0; d < e; d++) if (d % 4) { var g = f.indexOf(b.charAt(d - 1)) << 2 * (d % 4), h = f.indexOf(b.charAt(d)) >>> 6 - 2 * (d % 4); c[a >>> 2] |= (g | h) << 24 - 8 * (a % 4); a++ } return j.create(c, a) }, _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" } })();
+
+hawk.crypto.internals = CryptoJS;
+
+
+// Export if used as a module
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = hawk;
+}
+
+// $lab:coverage:on$
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/jquery-2.1.0.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;
+while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?o.queue(this[0],a):void 0===b?this:this.each(function(){var c=o.queue(this,a,b);o._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&o.dequeue(this,a)})},dequeue:function(a){return this.each(function(){o.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=o.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===o.css(a,"display")||!o.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=m.createDocumentFragment(),b=a.appendChild(m.createElement("div"));b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||m,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[o.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new o.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=m),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&o.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return o.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=o.extend(new o.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?o.event.trigger(e,null,b):o.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},o.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},o.Event=function(a,b){return this instanceof o.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.getPreventDefault&&a.getPreventDefault()?Z:$):this.type=a,b&&o.extend(this,b),this.timeStamp=a&&a.timeStamp||o.now(),void(this[o.expando]=!0)):new o.Event(a,b)},o.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z,this.stopPropagation()}},o.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){o.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!o.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.focusinBubbles||o.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){o.event.simulate(b,a.target,o.event.fix(a),!0)};o.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),o.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return o().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=o.guid++)),this.each(function(){o.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,o(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){o.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){o.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?o.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||o.contains(a.ownerDocument,a)||(g=o.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",e=m.documentElement,f=m.createElement("div"),g=m.createElement("div");g.style.backgroundClip="content-box",g.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===g.style.backgroundClip,f.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",f.appendChild(g);function h(){g.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",e.appendChild(f);var d=a.getComputedStyle(g,null);b="1%"!==d.top,c="4px"===d.width,e.removeChild(f)}a.getComputedStyle&&o.extend(l,{pixelPosition:function(){return h(),b},boxSizingReliable:function(){return null==c&&h(),c},reliableMarginRight:function(){var b,c=g.appendChild(m.createElement("div"));return c.style.cssText=g.style.cssText=d,c.style.marginRight=c.style.width="0",g.style.width="1px",e.appendChild(f),b=!parseFloat(a.getComputedStyle(c,null).marginRight),e.removeChild(f),g.innerHTML="",b}})}(),o.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:0,fontWeight:400},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=o.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=o.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=o.css(a,"border"+R[f]+"Width",!0,e))):(g+=o.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=o.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===o.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):f[g]||(e=S(d),(c&&"none"!==c||!e)&&L.set(d,"olddisplay",e?c:o.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}o.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=o.camelCase(b),i=a.style;return b=o.cssProps[h]||(o.cssProps[h]=Fb(i,h)),g=o.cssHooks[b]||o.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(o.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||o.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]="",i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=o.camelCase(b);return b=o.cssProps[h]||(o.cssProps[h]=Fb(a.style,h)),g=o.cssHooks[b]||o.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||o.isNumeric(f)?f||0:e):e}}),o.each(["height","width"],function(a,b){o.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&zb.test(o.css(a,"display"))?o.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===o.css(a,"boxSizing",!1,e),e):0)}}}),o.cssHooks.marginRight=yb(l.reliableMarginRight,function(a,b){return b?o.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),o.each({margin:"",padding:"",border:"Width"},function(a,b){o.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(o.cssHooks[a+b].set=Gb)}),o.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(o.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=o.css(a,b[g],!1,d);return f}return void 0!==c?o.style(a,b,c):o.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?o(this).show():o(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}o.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(o.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?o.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=o.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){o.fx.step[a.prop]?o.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[o.cssProps[a.prop]]||o.cssHooks[a.prop])?o.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},o.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},o.fx=Kb.prototype.init,o.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(o.cssNumber[a]?"":"px"),g=(o.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(o.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,o.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=o.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k=this,l={},m=a.style,n=a.nodeType&&S(a),p=L.get(a,"fxshow");c.queue||(h=o._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,k.always(function(){k.always(function(){h.unqueued--,o.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],j=o.css(a,"display"),"none"===j&&(j=tb(a.nodeName)),"inline"===j&&"none"===o.css(a,"float")&&(m.display="inline-block")),c.overflow&&(m.overflow="hidden",k.always(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(n?"hide":"show")){if("show"!==e||!p||void 0===p[d])continue;n=!0}l[d]=p&&p[d]||o.style(a,d)}if(!o.isEmptyObject(l)){p?"hidden"in p&&(n=p.hidden):p=L.access(a,"fxshow",{}),f&&(p.hidden=!n),n?o(a).show():k.done(function(){o(a).hide()}),k.done(function(){var b;L.remove(a,"fxshow");for(b in l)o.style(a,b,l[b])});for(d in l)g=Ub(n?p[d]:0,d,k),d in p||(p[d]=g.start,n&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=o.camelCase(c),e=b[d],f=a[c],o.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=o.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=o.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:o.extend({},b),opts:o.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=o.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return o.map(k,Ub,j),o.isFunction(j.opts.start)&&j.opts.start.call(a,j),o.fx.timer(o.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}o.Animation=o.extend(Xb,{tweener:function(a,b){o.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),o.speed=function(a,b,c){var d=a&&"object"==typeof a?o.extend({},a):{complete:c||!c&&b||o.isFunction(a)&&a,duration:a,easing:c&&b||b&&!o.isFunction(b)&&b};return d.duration=o.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in o.fx.speeds?o.fx.speeds[d.duration]:o.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){o.isFunction(d.old)&&d.old.call(this),d.queue&&o.dequeue(this,d.queue)},d},o.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=o.isEmptyObject(a),f=o.speed(b,c,d),g=function(){var b=Xb(this,o.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=o.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&o.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=o.timers,g=d?d.length:0;for(c.finish=!0,o.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),o.each(["toggle","show","hide"],function(a,b){var c=o.fn[b];o.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),o.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){o.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),o.timers=[],o.fx.tick=function(){var a,b=0,c=o.timers;for(Lb=o.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||o.fx.stop(),Lb=void 0},o.fx.timer=function(a){o.timers.push(a),a()?o.fx.start():o.timers.pop()},o.fx.interval=13,o.fx.start=function(){Mb||(Mb=setInterval(o.fx.tick,o.fx.interval))},o.fx.stop=function(){clearInterval(Mb),Mb=null},o.fx.speeds={slow:600,fast:200,_default:400},o.fn.delay=function(a,b){return a=o.fx?o.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=m.createElement("input"),b=m.createElement("select"),c=b.appendChild(m.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=m.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var Yb,Zb,$b=o.expr.attrHandle;o.fn.extend({attr:function(a,b){return J(this,o.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){o.removeAttr(this,a)})}}),o.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?o.prop(a,b,c):(1===f&&o.isXMLDoc(a)||(b=b.toLowerCase(),d=o.attrHooks[b]||(o.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=o.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void o.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=o.propFix[c]||c,o.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&o.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?o.removeAttr(a,c):a.setAttribute(c,c),c}},o.each(o.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||o.find.attr;$b[b]=function(a,b,d){var e,f;
+return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;o.fn.extend({prop:function(a,b){return J(this,o.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[o.propFix[a]||a]})}}),o.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!o.isXMLDoc(a),f&&(b=o.propFix[b]||b,e=o.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),l.optSelected||(o.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),o.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){o.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;o.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=o.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?o.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(o.isFunction(a)?function(c){o(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=o(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;o.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=o.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,o(this).val()):a,null==e?e="":"number"==typeof e?e+="":o.isArray(e)&&(e=o.map(e,function(a){return null==a?"":a+""})),b=o.valHooks[this.type]||o.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=o.valHooks[e.type]||o.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),o.extend({valHooks:{select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&o.nodeName(c.parentNode,"optgroup"))){if(b=o(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=o.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=o.inArray(o(d).val(),f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),o.each(["radio","checkbox"],function(){o.valHooks[this]={set:function(a,b){return o.isArray(b)?a.checked=o.inArray(o(a).val(),b)>=0:void 0}},l.checkOn||(o.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),o.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){o.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),o.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=o.now(),dc=/\?/;o.parseJSON=function(a){return JSON.parse(a+"")},o.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&o.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=m.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(o.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,o.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=o.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&o.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}o.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":o.parseJSON,"text xml":o.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,o.ajaxSettings),b):tc(o.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=o.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?o(l):o.event,n=o.Deferred(),p=o.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(n.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=o.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=o.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===o.active++&&o.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(o.lastModified[d]&&v.setRequestHeader("If-Modified-Since",o.lastModified[d]),o.etag[d]&&v.setRequestHeader("If-None-Match",o.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(o.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(o.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?n.resolveWith(l,[r,x,v]):n.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--o.active||o.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return o.get(a,b,c,"json")},getScript:function(a,b){return o.get(a,void 0,b,"script")}}),o.each(["get","post"],function(a,b){o[b]=function(a,c,d,e){return o.isFunction(c)&&(e=e||d,d=c,c=void 0),o.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),o.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){o.fn[b]=function(a){return this.on(b,a)}}),o._evalUrl=function(a){return o.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},o.fn.extend({wrapAll:function(a){var b;return o.isFunction(a)?this.each(function(b){o(this).wrapAll(a.call(this,b))}):(this[0]&&(b=o(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(o.isFunction(a)?function(b){o(this).wrapInner(a.call(this,b))}:function(){var b=o(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=o.isFunction(a);return this.each(function(c){o(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){o.nodeName(this,"body")||o(this).replaceWith(this.childNodes)}).end()}}),o.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},o.expr.filters.visible=function(a){return!o.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(o.isArray(b))o.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==o.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}o.param=function(a,b){var c,d=[],e=function(a,b){b=o.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=o.ajaxSettings&&o.ajaxSettings.traditional),o.isArray(a)||a.jquery&&!o.isPlainObject(a))o.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},o.fn.extend({serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=o.prop(this,"elements");return a?o.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!o(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=o(this).val();return null==c?null:o.isArray(c)?o.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),o.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=o.ajaxSettings.xhr();a.ActiveXObject&&o(a).on("unload",function(){for(var a in Dc)Dc[a]()}),l.cors=!!Fc&&"withCredentials"in Fc,l.ajax=Fc=!!Fc,o.ajaxTransport(function(a){var b;return l.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort"),f.send(a.hasContent&&a.data||null)},abort:function(){b&&b()}}:void 0}),o.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return o.globalEval(a),a}}}),o.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),o.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=o("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),m.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;o.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||o.expando+"_"+cc++;return this[a]=!0,a}}),o.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=o.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||o.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&o.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),o.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||m;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=o.buildFragment([a],b,e),e&&e.length&&o(e).remove(),o.merge([],d.childNodes))};var Ic=o.fn.load;o.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h),a=a.slice(0,h)),o.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&o.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?o("<div>").append(o.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},o.expr.filters.animated=function(a){return o.grep(o.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return o.isWindow(a)?a:9===a.nodeType&&a.defaultView}o.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=o.css(a,"position"),l=o(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=o.css(a,"top"),i=o.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),o.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},o.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){o.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,o.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===o.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),o.nodeName(a[0],"html")||(d=a.offset()),d.top+=o.css(a[0],"borderTopWidth",!0),d.left+=o.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-o.css(c,"marginTop",!0),left:b.left-d.left-o.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!o.nodeName(a,"html")&&"static"===o.css(a,"position"))a=a.offsetParent;return a||Jc})}}),o.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;o.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),o.each(["top","left"],function(a,b){o.cssHooks[b]=yb(l.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?o(a).position()[b]+"px":c):void 0})}),o.each({Height:"height",Width:"width"},function(a,b){o.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){o.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return o.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?o.css(b,c,g):o.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),o.fn.size=function(){return this.length},o.fn.andSelf=o.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return o});var Lc=a.jQuery,Mc=a.$;return o.noConflict=function(b){return a.$===o&&(a.$=Mc),b&&a.jQuery===o&&(a.jQuery=Lc),o},typeof b===U&&(a.jQuery=a.$=o),o});
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/lodash-2.4.1.js
@@ -0,0 +1,56 @@
+/**
+ * @license
+ * Lo-Dash 2.4.1 (Custom Build) lodash.com/license | Underscore.js 1.5.2 underscorejs.org/LICENSE
+ * Build: `lodash modern -o ./dist/lodash.js`
+ */
+;(function(){function n(n,t,e){e=(e||0)-1;for(var r=n?n.length:0;++e<r;)if(n[e]===t)return e;return-1}function t(t,e){var r=typeof e;if(t=t.l,"boolean"==r||null==e)return t[e]?0:-1;"number"!=r&&"string"!=r&&(r="object");var u="number"==r?e:m+e;return t=(t=t[r])&&t[u],"object"==r?t&&-1<n(t,e)?0:-1:t?0:-1}function e(n){var t=this.l,e=typeof n;if("boolean"==e||null==n)t[n]=true;else{"number"!=e&&"string"!=e&&(e="object");var r="number"==e?n:m+n,t=t[e]||(t[e]={});"object"==e?(t[r]||(t[r]=[])).push(n):t[r]=true
+}}function r(n){return n.charCodeAt(0)}function u(n,t){for(var e=n.m,r=t.m,u=-1,o=e.length;++u<o;){var i=e[u],a=r[u];if(i!==a){if(i>a||typeof i=="undefined")return 1;if(i<a||typeof a=="undefined")return-1}}return n.n-t.n}function o(n){var t=-1,r=n.length,u=n[0],o=n[r/2|0],i=n[r-1];if(u&&typeof u=="object"&&o&&typeof o=="object"&&i&&typeof i=="object")return false;for(u=f(),u["false"]=u["null"]=u["true"]=u.undefined=false,o=f(),o.k=n,o.l=u,o.push=e;++t<r;)o.push(n[t]);return o}function i(n){return"\\"+U[n]
+}function a(){return h.pop()||[]}function f(){return g.pop()||{k:null,l:null,m:null,"false":false,n:0,"null":false,number:null,object:null,push:null,string:null,"true":false,undefined:false,o:null}}function l(n){n.length=0,h.length<_&&h.push(n)}function c(n){var t=n.l;t&&c(t),n.k=n.l=n.m=n.object=n.number=n.string=n.o=null,g.length<_&&g.push(n)}function p(n,t,e){t||(t=0),typeof e=="undefined"&&(e=n?n.length:0);var r=-1;e=e-t||0;for(var u=Array(0>e?0:e);++r<e;)u[r]=n[t+r];return u}function s(e){function h(n,t,e){if(!n||!V[typeof n])return n;
+t=t&&typeof e=="undefined"?t:tt(t,e,3);for(var r=-1,u=V[typeof n]&&Fe(n),o=u?u.length:0;++r<o&&(e=u[r],false!==t(n[e],e,n)););return n}function g(n,t,e){var r;if(!n||!V[typeof n])return n;t=t&&typeof e=="undefined"?t:tt(t,e,3);for(r in n)if(false===t(n[r],r,n))break;return n}function _(n,t,e){var r,u=n,o=u;if(!u)return o;for(var i=arguments,a=0,f=typeof e=="number"?2:i.length;++a<f;)if((u=i[a])&&V[typeof u])for(var l=-1,c=V[typeof u]&&Fe(u),p=c?c.length:0;++l<p;)r=c[l],"undefined"==typeof o[r]&&(o[r]=u[r]);
+return o}function U(n,t,e){var r,u=n,o=u;if(!u)return o;var i=arguments,a=0,f=typeof e=="number"?2:i.length;if(3<f&&"function"==typeof i[f-2])var l=tt(i[--f-1],i[f--],2);else 2<f&&"function"==typeof i[f-1]&&(l=i[--f]);for(;++a<f;)if((u=i[a])&&V[typeof u])for(var c=-1,p=V[typeof u]&&Fe(u),s=p?p.length:0;++c<s;)r=p[c],o[r]=l?l(o[r],u[r]):u[r];return o}function H(n){var t,e=[];if(!n||!V[typeof n])return e;for(t in n)me.call(n,t)&&e.push(t);return e}function J(n){return n&&typeof n=="object"&&!Te(n)&&me.call(n,"__wrapped__")?n:new Q(n)
+}function Q(n,t){this.__chain__=!!t,this.__wrapped__=n}function X(n){function t(){if(r){var n=p(r);be.apply(n,arguments)}if(this instanceof t){var o=nt(e.prototype),n=e.apply(o,n||arguments);return wt(n)?n:o}return e.apply(u,n||arguments)}var e=n[0],r=n[2],u=n[4];return $e(t,n),t}function Z(n,t,e,r,u){if(e){var o=e(n);if(typeof o!="undefined")return o}if(!wt(n))return n;var i=ce.call(n);if(!K[i])return n;var f=Ae[i];switch(i){case T:case F:return new f(+n);case W:case P:return new f(n);case z:return o=f(n.source,C.exec(n)),o.lastIndex=n.lastIndex,o
+}if(i=Te(n),t){var c=!r;r||(r=a()),u||(u=a());for(var s=r.length;s--;)if(r[s]==n)return u[s];o=i?f(n.length):{}}else o=i?p(n):U({},n);return i&&(me.call(n,"index")&&(o.index=n.index),me.call(n,"input")&&(o.input=n.input)),t?(r.push(n),u.push(o),(i?St:h)(n,function(n,i){o[i]=Z(n,t,e,r,u)}),c&&(l(r),l(u)),o):o}function nt(n){return wt(n)?ke(n):{}}function tt(n,t,e){if(typeof n!="function")return Ut;if(typeof t=="undefined"||!("prototype"in n))return n;var r=n.__bindData__;if(typeof r=="undefined"&&(De.funcNames&&(r=!n.name),r=r||!De.funcDecomp,!r)){var u=ge.call(n);
+De.funcNames||(r=!O.test(u)),r||(r=E.test(u),$e(n,r))}if(false===r||true!==r&&1&r[1])return n;switch(e){case 1:return function(e){return n.call(t,e)};case 2:return function(e,r){return n.call(t,e,r)};case 3:return function(e,r,u){return n.call(t,e,r,u)};case 4:return function(e,r,u,o){return n.call(t,e,r,u,o)}}return Mt(n,t)}function et(n){function t(){var n=f?i:this;if(u){var h=p(u);be.apply(h,arguments)}return(o||c)&&(h||(h=p(arguments)),o&&be.apply(h,o),c&&h.length<a)?(r|=16,et([e,s?r:-4&r,h,null,i,a])):(h||(h=arguments),l&&(e=n[v]),this instanceof t?(n=nt(e.prototype),h=e.apply(n,h),wt(h)?h:n):e.apply(n,h))
+}var e=n[0],r=n[1],u=n[2],o=n[3],i=n[4],a=n[5],f=1&r,l=2&r,c=4&r,s=8&r,v=e;return $e(t,n),t}function rt(e,r){var u=-1,i=st(),a=e?e.length:0,f=a>=b&&i===n,l=[];if(f){var p=o(r);p?(i=t,r=p):f=false}for(;++u<a;)p=e[u],0>i(r,p)&&l.push(p);return f&&c(r),l}function ut(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r<u;){var i=n[r];if(i&&typeof i=="object"&&typeof i.length=="number"&&(Te(i)||yt(i))){t||(i=ut(i,t,e));var a=-1,f=i.length,l=o.length;for(o.length+=f;++a<f;)o[l++]=i[a]}else e||o.push(i)}return o
+}function ot(n,t,e,r,u,o){if(e){var i=e(n,t);if(typeof i!="undefined")return!!i}if(n===t)return 0!==n||1/n==1/t;if(n===n&&!(n&&V[typeof n]||t&&V[typeof t]))return false;if(null==n||null==t)return n===t;var f=ce.call(n),c=ce.call(t);if(f==D&&(f=q),c==D&&(c=q),f!=c)return false;switch(f){case T:case F:return+n==+t;case W:return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case z:case P:return n==oe(t)}if(c=f==$,!c){var p=me.call(n,"__wrapped__"),s=me.call(t,"__wrapped__");if(p||s)return ot(p?n.__wrapped__:n,s?t.__wrapped__:t,e,r,u,o);
+if(f!=q)return false;if(f=n.constructor,p=t.constructor,f!=p&&!(dt(f)&&f instanceof f&&dt(p)&&p instanceof p)&&"constructor"in n&&"constructor"in t)return false}for(f=!u,u||(u=a()),o||(o=a()),p=u.length;p--;)if(u[p]==n)return o[p]==t;var v=0,i=true;if(u.push(n),o.push(t),c){if(p=n.length,v=t.length,(i=v==p)||r)for(;v--;)if(c=p,s=t[v],r)for(;c--&&!(i=ot(n[c],s,e,r,u,o)););else if(!(i=ot(n[v],s,e,r,u,o)))break}else g(t,function(t,a,f){return me.call(f,a)?(v++,i=me.call(n,a)&&ot(n[a],t,e,r,u,o)):void 0}),i&&!r&&g(n,function(n,t,e){return me.call(e,t)?i=-1<--v:void 0
+});return u.pop(),o.pop(),f&&(l(u),l(o)),i}function it(n,t,e,r,u){(Te(t)?St:h)(t,function(t,o){var i,a,f=t,l=n[o];if(t&&((a=Te(t))||Pe(t))){for(f=r.length;f--;)if(i=r[f]==t){l=u[f];break}if(!i){var c;e&&(f=e(l,t),c=typeof f!="undefined")&&(l=f),c||(l=a?Te(l)?l:[]:Pe(l)?l:{}),r.push(t),u.push(l),c||it(l,t,e,r,u)}}else e&&(f=e(l,t),typeof f=="undefined"&&(f=t)),typeof f!="undefined"&&(l=f);n[o]=l})}function at(n,t){return n+he(Re()*(t-n+1))}function ft(e,r,u){var i=-1,f=st(),p=e?e.length:0,s=[],v=!r&&p>=b&&f===n,h=u||v?a():s;
+for(v&&(h=o(h),f=t);++i<p;){var g=e[i],y=u?u(g,i,e):g;(r?!i||h[h.length-1]!==y:0>f(h,y))&&((u||v)&&h.push(y),s.push(g))}return v?(l(h.k),c(h)):u&&l(h),s}function lt(n){return function(t,e,r){var u={};e=J.createCallback(e,r,3),r=-1;var o=t?t.length:0;if(typeof o=="number")for(;++r<o;){var i=t[r];n(u,i,e(i,r,t),t)}else h(t,function(t,r,o){n(u,t,e(t,r,o),o)});return u}}function ct(n,t,e,r,u,o){var i=1&t,a=4&t,f=16&t,l=32&t;if(!(2&t||dt(n)))throw new ie;f&&!e.length&&(t&=-17,f=e=false),l&&!r.length&&(t&=-33,l=r=false);
+var c=n&&n.__bindData__;return c&&true!==c?(c=p(c),c[2]&&(c[2]=p(c[2])),c[3]&&(c[3]=p(c[3])),!i||1&c[1]||(c[4]=u),!i&&1&c[1]&&(t|=8),!a||4&c[1]||(c[5]=o),f&&be.apply(c[2]||(c[2]=[]),e),l&&we.apply(c[3]||(c[3]=[]),r),c[1]|=t,ct.apply(null,c)):(1==t||17===t?X:et)([n,t,e,r,u,o])}function pt(n){return Be[n]}function st(){var t=(t=J.indexOf)===Wt?n:t;return t}function vt(n){return typeof n=="function"&&pe.test(n)}function ht(n){var t,e;return n&&ce.call(n)==q&&(t=n.constructor,!dt(t)||t instanceof t)?(g(n,function(n,t){e=t
+}),typeof e=="undefined"||me.call(n,e)):false}function gt(n){return We[n]}function yt(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ce.call(n)==D||false}function mt(n,t,e){var r=Fe(n),u=r.length;for(t=tt(t,e,3);u--&&(e=r[u],false!==t(n[e],e,n)););return n}function bt(n){var t=[];return g(n,function(n,e){dt(n)&&t.push(e)}),t.sort()}function _t(n){for(var t=-1,e=Fe(n),r=e.length,u={};++t<r;){var o=e[t];u[n[o]]=o}return u}function dt(n){return typeof n=="function"}function wt(n){return!(!n||!V[typeof n])
+}function jt(n){return typeof n=="number"||n&&typeof n=="object"&&ce.call(n)==W||false}function kt(n){return typeof n=="string"||n&&typeof n=="object"&&ce.call(n)==P||false}function xt(n){for(var t=-1,e=Fe(n),r=e.length,u=Xt(r);++t<r;)u[t]=n[e[t]];return u}function Ct(n,t,e){var r=-1,u=st(),o=n?n.length:0,i=false;return e=(0>e?Ie(0,o+e):e)||0,Te(n)?i=-1<u(n,t,e):typeof o=="number"?i=-1<(kt(n)?n.indexOf(t,e):u(n,t,e)):h(n,function(n){return++r<e?void 0:!(i=n===t)}),i}function Ot(n,t,e){var r=true;t=J.createCallback(t,e,3),e=-1;
+var u=n?n.length:0;if(typeof u=="number")for(;++e<u&&(r=!!t(n[e],e,n)););else h(n,function(n,e,u){return r=!!t(n,e,u)});return r}function Nt(n,t,e){var r=[];t=J.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e<u;){var o=n[e];t(o,e,n)&&r.push(o)}else h(n,function(n,e,u){t(n,e,u)&&r.push(n)});return r}function It(n,t,e){t=J.createCallback(t,e,3),e=-1;var r=n?n.length:0;if(typeof r!="number"){var u;return h(n,function(n,e,r){return t(n,e,r)?(u=n,false):void 0}),u}for(;++e<r;){var o=n[e];
+if(t(o,e,n))return o}}function St(n,t,e){var r=-1,u=n?n.length:0;if(t=t&&typeof e=="undefined"?t:tt(t,e,3),typeof u=="number")for(;++r<u&&false!==t(n[r],r,n););else h(n,t);return n}function Et(n,t,e){var r=n?n.length:0;if(t=t&&typeof e=="undefined"?t:tt(t,e,3),typeof r=="number")for(;r--&&false!==t(n[r],r,n););else{var u=Fe(n),r=u.length;h(n,function(n,e,o){return e=u?u[--r]:--r,t(o[e],e,o)})}return n}function Rt(n,t,e){var r=-1,u=n?n.length:0;if(t=J.createCallback(t,e,3),typeof u=="number")for(var o=Xt(u);++r<u;)o[r]=t(n[r],r,n);
+else o=[],h(n,function(n,e,u){o[++r]=t(n,e,u)});return o}function At(n,t,e){var u=-1/0,o=u;if(typeof t!="function"&&e&&e[t]===n&&(t=null),null==t&&Te(n)){e=-1;for(var i=n.length;++e<i;){var a=n[e];a>o&&(o=a)}}else t=null==t&&kt(n)?r:J.createCallback(t,e,3),St(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Dt(n,t,e,r){if(!n)return e;var u=3>arguments.length;t=J.createCallback(t,r,4);var o=-1,i=n.length;if(typeof i=="number")for(u&&(e=n[++o]);++o<i;)e=t(e,n[o],o,n);else h(n,function(n,r,o){e=u?(u=false,n):t(e,n,r,o)
+});return e}function $t(n,t,e,r){var u=3>arguments.length;return t=J.createCallback(t,r,4),Et(n,function(n,r,o){e=u?(u=false,n):t(e,n,r,o)}),e}function Tt(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return St(n,function(n){var e=at(0,++t);r[t]=r[e],r[e]=n}),r}function Ft(n,t,e){var r;t=J.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e<u&&!(r=t(n[e],e,n)););else h(n,function(n,e,u){return!(r=t(n,e,u))});return!!r}function Bt(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=-1;
+for(t=J.createCallback(t,e,3);++o<u&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[0]:v;return p(n,0,Se(Ie(0,r),u))}function Wt(t,e,r){if(typeof r=="number"){var u=t?t.length:0;r=0>r?Ie(0,u+r):r||0}else if(r)return r=zt(t,e),t[r]===e?r:-1;return n(t,e,r)}function qt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=J.createCallback(t,e,3);++u<o&&t(n[u],u,n);)r++}else r=null==t||e?1:Ie(0,t);return p(n,r)}function zt(n,t,e,r){var u=0,o=n?n.length:u;for(e=e?J.createCallback(e,r,1):Ut,t=e(t);u<o;)r=u+o>>>1,e(n[r])<t?u=r+1:o=r;
+return u}function Pt(n,t,e,r){return typeof t!="boolean"&&null!=t&&(r=e,e=typeof t!="function"&&r&&r[t]===n?null:t,t=false),null!=e&&(e=J.createCallback(e,r,3)),ft(n,t,e)}function Kt(){for(var n=1<arguments.length?arguments:arguments[0],t=-1,e=n?At(Ve(n,"length")):0,r=Xt(0>e?0:e);++t<e;)r[t]=Ve(n,t);return r}function Lt(n,t){var e=-1,r=n?n.length:0,u={};for(t||!r||Te(n[0])||(t=[]);++e<r;){var o=n[e];t?u[o]=t[e]:o&&(u[o[0]]=o[1])}return u}function Mt(n,t){return 2<arguments.length?ct(n,17,p(arguments,2),null,t):ct(n,1,null,null,t)
+}function Vt(n,t,e){function r(){c&&ve(c),i=c=p=v,(g||h!==t)&&(s=Ue(),a=n.apply(l,o),c||i||(o=l=null))}function u(){var e=t-(Ue()-f);0<e?c=_e(u,e):(i&&ve(i),e=p,i=c=p=v,e&&(s=Ue(),a=n.apply(l,o),c||i||(o=l=null)))}var o,i,a,f,l,c,p,s=0,h=false,g=true;if(!dt(n))throw new ie;if(t=Ie(0,t)||0,true===e)var y=true,g=false;else wt(e)&&(y=e.leading,h="maxWait"in e&&(Ie(t,e.maxWait)||0),g="trailing"in e?e.trailing:g);return function(){if(o=arguments,f=Ue(),l=this,p=g&&(c||!y),false===h)var e=y&&!c;else{i||y||(s=f);var v=h-(f-s),m=0>=v;
+m?(i&&(i=ve(i)),s=f,a=n.apply(l,o)):i||(i=_e(r,v))}return m&&c?c=ve(c):c||t===h||(c=_e(u,t)),e&&(m=true,a=n.apply(l,o)),!m||c||i||(o=l=null),a}}function Ut(n){return n}function Gt(n,t,e){var r=true,u=t&&bt(t);t&&(e||u.length)||(null==e&&(e=t),o=Q,t=n,n=J,u=bt(t)),false===e?r=false:wt(e)&&"chain"in e&&(r=e.chain);var o=n,i=dt(o);St(u,function(e){var u=n[e]=t[e];i&&(o.prototype[e]=function(){var t=this.__chain__,e=this.__wrapped__,i=[e];if(be.apply(i,arguments),i=u.apply(n,i),r||t){if(e===i&&wt(i))return this;
+i=new o(i),i.__chain__=t}return i})})}function Ht(){}function Jt(n){return function(t){return t[n]}}function Qt(){return this.__wrapped__}e=e?Y.defaults(G.Object(),e,Y.pick(G,A)):G;var Xt=e.Array,Yt=e.Boolean,Zt=e.Date,ne=e.Function,te=e.Math,ee=e.Number,re=e.Object,ue=e.RegExp,oe=e.String,ie=e.TypeError,ae=[],fe=re.prototype,le=e._,ce=fe.toString,pe=ue("^"+oe(ce).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$"),se=te.ceil,ve=e.clearTimeout,he=te.floor,ge=ne.prototype.toString,ye=vt(ye=re.getPrototypeOf)&&ye,me=fe.hasOwnProperty,be=ae.push,_e=e.setTimeout,de=ae.splice,we=ae.unshift,je=function(){try{var n={},t=vt(t=re.defineProperty)&&t,e=t(n,n,n)&&t
+}catch(r){}return e}(),ke=vt(ke=re.create)&&ke,xe=vt(xe=Xt.isArray)&&xe,Ce=e.isFinite,Oe=e.isNaN,Ne=vt(Ne=re.keys)&&Ne,Ie=te.max,Se=te.min,Ee=e.parseInt,Re=te.random,Ae={};Ae[$]=Xt,Ae[T]=Yt,Ae[F]=Zt,Ae[B]=ne,Ae[q]=re,Ae[W]=ee,Ae[z]=ue,Ae[P]=oe,Q.prototype=J.prototype;var De=J.support={};De.funcDecomp=!vt(e.a)&&E.test(s),De.funcNames=typeof ne.name=="string",J.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:J}},ke||(nt=function(){function n(){}return function(t){if(wt(t)){n.prototype=t;
+var r=new n;n.prototype=null}return r||e.Object()}}());var $e=je?function(n,t){M.value=t,je(n,"__bindData__",M)}:Ht,Te=xe||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ce.call(n)==$||false},Fe=Ne?function(n){return wt(n)?Ne(n):[]}:H,Be={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},We=_t(Be),qe=ue("("+Fe(We).join("|")+")","g"),ze=ue("["+Fe(Be).join("")+"]","g"),Pe=ye?function(n){if(!n||ce.call(n)!=q)return false;var t=n.valueOf,e=vt(t)&&(e=ye(t))&&ye(e);return e?n==e||ye(n)==e:ht(n)
+}:ht,Ke=lt(function(n,t,e){me.call(n,e)?n[e]++:n[e]=1}),Le=lt(function(n,t,e){(me.call(n,e)?n[e]:n[e]=[]).push(t)}),Me=lt(function(n,t,e){n[e]=t}),Ve=Rt,Ue=vt(Ue=Zt.now)&&Ue||function(){return(new Zt).getTime()},Ge=8==Ee(d+"08")?Ee:function(n,t){return Ee(kt(n)?n.replace(I,""):n,t||0)};return J.after=function(n,t){if(!dt(t))throw new ie;return function(){return 1>--n?t.apply(this,arguments):void 0}},J.assign=U,J.at=function(n){for(var t=arguments,e=-1,r=ut(t,true,false,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=Xt(t);++e<t;)u[e]=n[r[e]];
+return u},J.bind=Mt,J.bindAll=function(n){for(var t=1<arguments.length?ut(arguments,true,false,1):bt(n),e=-1,r=t.length;++e<r;){var u=t[e];n[u]=ct(n[u],1,null,null,n)}return n},J.bindKey=function(n,t){return 2<arguments.length?ct(t,19,p(arguments,2),null,n):ct(t,3,null,null,n)},J.chain=function(n){return n=new Q(n),n.__chain__=true,n},J.compact=function(n){for(var t=-1,e=n?n.length:0,r=[];++t<e;){var u=n[t];u&&r.push(u)}return r},J.compose=function(){for(var n=arguments,t=n.length;t--;)if(!dt(n[t]))throw new ie;
+return function(){for(var t=arguments,e=n.length;e--;)t=[n[e].apply(this,t)];return t[0]}},J.constant=function(n){return function(){return n}},J.countBy=Ke,J.create=function(n,t){var e=nt(n);return t?U(e,t):e},J.createCallback=function(n,t,e){var r=typeof n;if(null==n||"function"==r)return tt(n,t,e);if("object"!=r)return Jt(n);var u=Fe(n),o=u[0],i=n[o];return 1!=u.length||i!==i||wt(i)?function(t){for(var e=u.length,r=false;e--&&(r=ot(t[u[e]],n[u[e]],null,true)););return r}:function(n){return n=n[o],i===n&&(0!==i||1/i==1/n)
+}},J.curry=function(n,t){return t=typeof t=="number"?t:+t||n.length,ct(n,4,null,null,null,t)},J.debounce=Vt,J.defaults=_,J.defer=function(n){if(!dt(n))throw new ie;var t=p(arguments,1);return _e(function(){n.apply(v,t)},1)},J.delay=function(n,t){if(!dt(n))throw new ie;var e=p(arguments,2);return _e(function(){n.apply(v,e)},t)},J.difference=function(n){return rt(n,ut(arguments,true,true,1))},J.filter=Nt,J.flatten=function(n,t,e,r){return typeof t!="boolean"&&null!=t&&(r=e,e=typeof t!="function"&&r&&r[t]===n?null:t,t=false),null!=e&&(n=Rt(n,e,r)),ut(n,t)
+},J.forEach=St,J.forEachRight=Et,J.forIn=g,J.forInRight=function(n,t,e){var r=[];g(n,function(n,t){r.push(t,n)});var u=r.length;for(t=tt(t,e,3);u--&&false!==t(r[u--],r[u],n););return n},J.forOwn=h,J.forOwnRight=mt,J.functions=bt,J.groupBy=Le,J.indexBy=Me,J.initial=function(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=u;for(t=J.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else r=null==t||e?1:t||r;return p(n,0,Se(Ie(0,u-r),u))},J.intersection=function(){for(var e=[],r=-1,u=arguments.length,i=a(),f=st(),p=f===n,s=a();++r<u;){var v=arguments[r];
+(Te(v)||yt(v))&&(e.push(v),i.push(p&&v.length>=b&&o(r?e[r]:s)))}var p=e[0],h=-1,g=p?p.length:0,y=[];n:for(;++h<g;){var m=i[0],v=p[h];if(0>(m?t(m,v):f(s,v))){for(r=u,(m||s).push(v);--r;)if(m=i[r],0>(m?t(m,v):f(e[r],v)))continue n;y.push(v)}}for(;u--;)(m=i[u])&&c(m);return l(i),l(s),y},J.invert=_t,J.invoke=function(n,t){var e=p(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,i=Xt(typeof o=="number"?o:0);return St(n,function(n){i[++r]=(u?t:n[t]).apply(n,e)}),i},J.keys=Fe,J.map=Rt,J.mapValues=function(n,t,e){var r={};
+return t=J.createCallback(t,e,3),h(n,function(n,e,u){r[e]=t(n,e,u)}),r},J.max=At,J.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):m+arguments[0];return me.call(r,u)?r[u]:r[u]=n.apply(this,arguments)}if(!dt(n))throw new ie;return e.cache={},e},J.merge=function(n){var t=arguments,e=2;if(!wt(n))return n;if("number"!=typeof t[2]&&(e=t.length),3<e&&"function"==typeof t[e-2])var r=tt(t[--e-1],t[e--],2);else 2<e&&"function"==typeof t[e-1]&&(r=t[--e]);for(var t=p(arguments,1,e),u=-1,o=a(),i=a();++u<e;)it(n,t[u],r,o,i);
+return l(o),l(i),n},J.min=function(n,t,e){var u=1/0,o=u;if(typeof t!="function"&&e&&e[t]===n&&(t=null),null==t&&Te(n)){e=-1;for(var i=n.length;++e<i;){var a=n[e];a<o&&(o=a)}}else t=null==t&&kt(n)?r:J.createCallback(t,e,3),St(n,function(n,e,r){e=t(n,e,r),e<u&&(u=e,o=n)});return o},J.omit=function(n,t,e){var r={};if(typeof t!="function"){var u=[];g(n,function(n,t){u.push(t)});for(var u=rt(u,ut(arguments,true,false,1)),o=-1,i=u.length;++o<i;){var a=u[o];r[a]=n[a]}}else t=J.createCallback(t,e,3),g(n,function(n,e,u){t(n,e,u)||(r[e]=n)
+});return r},J.once=function(n){var t,e;if(!dt(n))throw new ie;return function(){return t?e:(t=true,e=n.apply(this,arguments),n=null,e)}},J.pairs=function(n){for(var t=-1,e=Fe(n),r=e.length,u=Xt(r);++t<r;){var o=e[t];u[t]=[o,n[o]]}return u},J.partial=function(n){return ct(n,16,p(arguments,1))},J.partialRight=function(n){return ct(n,32,null,p(arguments,1))},J.pick=function(n,t,e){var r={};if(typeof t!="function")for(var u=-1,o=ut(arguments,true,false,1),i=wt(n)?o.length:0;++u<i;){var a=o[u];a in n&&(r[a]=n[a])
+}else t=J.createCallback(t,e,3),g(n,function(n,e,u){t(n,e,u)&&(r[e]=n)});return r},J.pluck=Ve,J.property=Jt,J.pull=function(n){for(var t=arguments,e=0,r=t.length,u=n?n.length:0;++e<r;)for(var o=-1,i=t[e];++o<u;)n[o]===i&&(de.call(n,o--,1),u--);return n},J.range=function(n,t,e){n=+n||0,e=typeof e=="number"?e:+e||1,null==t&&(t=n,n=0);var r=-1;t=Ie(0,se((t-n)/(e||1)));for(var u=Xt(t);++r<t;)u[r]=n,n+=e;return u},J.reject=function(n,t,e){return t=J.createCallback(t,e,3),Nt(n,function(n,e,r){return!t(n,e,r)
+})},J.remove=function(n,t,e){var r=-1,u=n?n.length:0,o=[];for(t=J.createCallback(t,e,3);++r<u;)e=n[r],t(e,r,n)&&(o.push(e),de.call(n,r--,1),u--);return o},J.rest=qt,J.shuffle=Tt,J.sortBy=function(n,t,e){var r=-1,o=Te(t),i=n?n.length:0,p=Xt(typeof i=="number"?i:0);for(o||(t=J.createCallback(t,e,3)),St(n,function(n,e,u){var i=p[++r]=f();o?i.m=Rt(t,function(t){return n[t]}):(i.m=a())[0]=t(n,e,u),i.n=r,i.o=n}),i=p.length,p.sort(u);i--;)n=p[i],p[i]=n.o,o||l(n.m),c(n);return p},J.tap=function(n,t){return t(n),n
+},J.throttle=function(n,t,e){var r=true,u=true;if(!dt(n))throw new ie;return false===e?r=false:wt(e)&&(r="leading"in e?e.leading:r,u="trailing"in e?e.trailing:u),L.leading=r,L.maxWait=t,L.trailing=u,Vt(n,t,L)},J.times=function(n,t,e){n=-1<(n=+n)?n:0;var r=-1,u=Xt(n);for(t=tt(t,e,1);++r<n;)u[r]=t(r);return u},J.toArray=function(n){return n&&typeof n.length=="number"?p(n):xt(n)},J.transform=function(n,t,e,r){var u=Te(n);if(null==e)if(u)e=[];else{var o=n&&n.constructor;e=nt(o&&o.prototype)}return t&&(t=J.createCallback(t,r,4),(u?St:h)(n,function(n,r,u){return t(e,n,r,u)
+})),e},J.union=function(){return ft(ut(arguments,true,true))},J.uniq=Pt,J.values=xt,J.where=Nt,J.without=function(n){return rt(n,p(arguments,1))},J.wrap=function(n,t){return ct(t,16,[n])},J.xor=function(){for(var n=-1,t=arguments.length;++n<t;){var e=arguments[n];if(Te(e)||yt(e))var r=r?ft(rt(r,e).concat(rt(e,r))):e}return r||[]},J.zip=Kt,J.zipObject=Lt,J.collect=Rt,J.drop=qt,J.each=St,J.eachRight=Et,J.extend=U,J.methods=bt,J.object=Lt,J.select=Nt,J.tail=qt,J.unique=Pt,J.unzip=Kt,Gt(J),J.clone=function(n,t,e,r){return typeof t!="boolean"&&null!=t&&(r=e,e=t,t=false),Z(n,t,typeof e=="function"&&tt(e,r,1))
+},J.cloneDeep=function(n,t,e){return Z(n,true,typeof t=="function"&&tt(t,e,1))},J.contains=Ct,J.escape=function(n){return null==n?"":oe(n).replace(ze,pt)},J.every=Ot,J.find=It,J.findIndex=function(n,t,e){var r=-1,u=n?n.length:0;for(t=J.createCallback(t,e,3);++r<u;)if(t(n[r],r,n))return r;return-1},J.findKey=function(n,t,e){var r;return t=J.createCallback(t,e,3),h(n,function(n,e,u){return t(n,e,u)?(r=e,false):void 0}),r},J.findLast=function(n,t,e){var r;return t=J.createCallback(t,e,3),Et(n,function(n,e,u){return t(n,e,u)?(r=n,false):void 0
+}),r},J.findLastIndex=function(n,t,e){var r=n?n.length:0;for(t=J.createCallback(t,e,3);r--;)if(t(n[r],r,n))return r;return-1},J.findLastKey=function(n,t,e){var r;return t=J.createCallback(t,e,3),mt(n,function(n,e,u){return t(n,e,u)?(r=e,false):void 0}),r},J.has=function(n,t){return n?me.call(n,t):false},J.identity=Ut,J.indexOf=Wt,J.isArguments=yt,J.isArray=Te,J.isBoolean=function(n){return true===n||false===n||n&&typeof n=="object"&&ce.call(n)==T||false},J.isDate=function(n){return n&&typeof n=="object"&&ce.call(n)==F||false
+},J.isElement=function(n){return n&&1===n.nodeType||false},J.isEmpty=function(n){var t=true;if(!n)return t;var e=ce.call(n),r=n.length;return e==$||e==P||e==D||e==q&&typeof r=="number"&&dt(n.splice)?!r:(h(n,function(){return t=false}),t)},J.isEqual=function(n,t,e,r){return ot(n,t,typeof e=="function"&&tt(e,r,2))},J.isFinite=function(n){return Ce(n)&&!Oe(parseFloat(n))},J.isFunction=dt,J.isNaN=function(n){return jt(n)&&n!=+n},J.isNull=function(n){return null===n},J.isNumber=jt,J.isObject=wt,J.isPlainObject=Pe,J.isRegExp=function(n){return n&&typeof n=="object"&&ce.call(n)==z||false
+},J.isString=kt,J.isUndefined=function(n){return typeof n=="undefined"},J.lastIndexOf=function(n,t,e){var r=n?n.length:0;for(typeof e=="number"&&(r=(0>e?Ie(0,r+e):Se(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},J.mixin=Gt,J.noConflict=function(){return e._=le,this},J.noop=Ht,J.now=Ue,J.parseInt=Ge,J.random=function(n,t,e){var r=null==n,u=null==t;return null==e&&(typeof n=="boolean"&&u?(e=n,n=1):u||typeof t!="boolean"||(e=t,u=true)),r&&u&&(t=1),n=+n||0,u?(t=n,n=0):t=+t||0,e||n%1||t%1?(e=Re(),Se(n+e*(t-n+parseFloat("1e-"+((e+"").length-1))),t)):at(n,t)
+},J.reduce=Dt,J.reduceRight=$t,J.result=function(n,t){if(n){var e=n[t];return dt(e)?n[t]():e}},J.runInContext=s,J.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Fe(n).length},J.some=Ft,J.sortedIndex=zt,J.template=function(n,t,e){var r=J.templateSettings;n=oe(n||""),e=_({},e,r);var u,o=_({},e.imports,r.imports),r=Fe(o),o=xt(o),a=0,f=e.interpolate||S,l="__p+='",f=ue((e.escape||S).source+"|"+f.source+"|"+(f===N?x:S).source+"|"+(e.evaluate||S).source+"|$","g");n.replace(f,function(t,e,r,o,f,c){return r||(r=o),l+=n.slice(a,c).replace(R,i),e&&(l+="'+__e("+e+")+'"),f&&(u=true,l+="';"+f+";\n__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),a=c+t.length,t
+}),l+="';",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(w,""):l).replace(j,"$1").replace(k,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}";try{var c=ne(r,"return "+l).apply(v,o)}catch(p){throw p.source=l,p}return t?c(t):(c.source=l,c)},J.unescape=function(n){return null==n?"":oe(n).replace(qe,gt)},J.uniqueId=function(n){var t=++y;return oe(null==n?"":n)+t
+},J.all=Ot,J.any=Ft,J.detect=It,J.findWhere=It,J.foldl=Dt,J.foldr=$t,J.include=Ct,J.inject=Dt,Gt(function(){var n={};return h(J,function(t,e){J.prototype[e]||(n[e]=t)}),n}(),false),J.first=Bt,J.last=function(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=u;for(t=J.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:v;return p(n,Ie(0,u-r))},J.sample=function(n,t,e){return n&&typeof n.length!="number"&&(n=xt(n)),null==t||e?n?n[at(0,n.length-1)]:v:(n=Tt(n),n.length=Se(Ie(0,t),n.length),n)
+},J.take=Bt,J.head=Bt,h(J,function(n,t){var e="sample"!==t;J.prototype[t]||(J.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new Q(o,u):o})}),J.VERSION="2.4.1",J.prototype.chain=function(){return this.__chain__=true,this},J.prototype.toString=function(){return oe(this.__wrapped__)},J.prototype.value=Qt,J.prototype.valueOf=Qt,St(["join","pop","shift"],function(n){var t=ae[n];J.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments);
+return n?new Q(e,n):e}}),St(["push","reverse","sort","unshift"],function(n){var t=ae[n];J.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),St(["concat","slice","splice"],function(n){var t=ae[n];J.prototype[n]=function(){return new Q(t.apply(this.__wrapped__,arguments),this.__chain__)}}),J}var v,h=[],g=[],y=0,m=+new Date+"",b=75,_=40,d=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",w=/\b__p\+='';/g,j=/\b(__p\+=)''\+/g,k=/(__e\(.*?\)|\b__t\))\+'';/g,x=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,C=/\w*$/,O=/^\s*function[ \n\r\t]+\w/,N=/<%=([\s\S]+?)%>/g,I=RegExp("^["+d+"]*0+(?=.$)"),S=/($^)/,E=/\bthis\b/,R=/['\n\r\t\u2028\u2029\\]/g,A="Array Boolean Date Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setTimeout".split(" "),D="[object Arguments]",$="[object Array]",T="[object Boolean]",F="[object Date]",B="[object Function]",W="[object Number]",q="[object Object]",z="[object RegExp]",P="[object String]",K={};
+K[B]=false,K[D]=K[$]=K[T]=K[F]=K[W]=K[q]=K[z]=K[P]=true;var L={leading:false,maxWait:0,trailing:false},M={configurable:false,enumerable:false,value:null,writable:false},V={"boolean":false,"function":true,object:true,number:false,string:false,undefined:false},U={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},G=V[typeof window]&&window||this,H=V[typeof exports]&&exports&&!exports.nodeType&&exports,J=V[typeof module]&&module&&!module.nodeType&&module,Q=J&&J.exports===H&&H,X=V[typeof global]&&global;!X||X.global!==X&&X.window!==X||(G=X);
+var Y=s();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(G._=Y, define(function(){return Y})):H&&J?Q?(J.exports=Y)._=Y:H._=Y:G._=Y}).call(this);
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/otcdn/webrtc/v2.2.5/css/ot.min.css
@@ -0,0 +1,12 @@
+/**
+ * @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_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)}
new file mode 100644
index 0000000000000000000000000000000000000000..777e02f1a8b329949b9661b20190274a46c3f178
GIT binary patch
literal 10531
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
new file mode 100644
index 0000000000000000000000000000000000000000..18b494e7e672e43f4c244411606ea973bff9b53a
GIT binary patch
literal 6556
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
O0000<MNUMnLSTX&q651C
new file mode 100644
index 0000000000000000000000000000000000000000..cc6bebe9632ecba852e800f7c6e6f3eea0953d01
GIT binary patch
literal 7871
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
new file mode 100644
index 0000000000000000000000000000000000000000..9e23411986733d0a982cf334608ed951ea6af1c7
GIT binary patch
literal 9563
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%0A6{1Jvkvn5+0=g`GXip$%
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
FV1mIKt7iZJ
new file mode 100644
index 0000000000000000000000000000000000000000..6728fe807f59bf4f41c29da27887256caba86d02
GIT binary patch
literal 19523
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
new file mode 100644
index 0000000000000000000000000000000000000000..24c9a7cb90e105f636fc0ba658cd6bc29b1425fc
GIT binary patch
literal 1389
zc$@)k1(N!SP)<h;3K|Lk000e1NJLTq000yK001Ef1^@s6**=RC00004b3#c}2nYxW
zd<bNS00009a7bBm000XT000XT0n*)m`~Uy|6m&&cbVG7wVRUJ4ZXi@?ZDjy6FE=kS
zGffYRzW@LL9CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?ocW-iQb09-gHF34$HUIzw$4Nv%
zR7i=Pm0N5TRTPH5J=b%;&<h1DK}|^TfgqS5Aqrjs0wN897a$D=0uK@^SP2jw5YZMy
z0<j^fnxGH~MUlo73JHmq;ENg&F)>6)Fe*VxdwQKSGv~}~ALg_iN@-J9GPC#0?Ejy&
z{<ZdAf>GM0Iy7D9Mkq>J)%eZ#IPN%nP*+1YfEX=dzwJFrBphXy^x5b-Ott!0w0#Yi
zMon0|hnZ%WCD9m{jSwelU#7RAnXN+M^_~n5DWfG60!!1#sXD8G%e#*-b3+w%exC0V
zX}16GkO3M_vKGNxRxgu%j~THPNAF3vsh(0*rN%H>tQ*{~s@M{K_B=k#yEMJ?8WLdt
z7hKSFcJ*{|RyXdUVeM{aYX&D1Y08pmh{i!P010*$dOA7PmEnaQ>#=rz#EN8^-)oj}
z0fxx(8}(EgVJ?-Fkt`n%i8L4{s9Hdn&x2(_rj5_mJ;SQO_`8y#YHUrWNLExrNd-h=
zpc^0r2ql;&l2AU5m5ryEHX@;J@@%ps@Ju&~Vi314As`ZkR0)elBs5GWMB|{FL#Z2t
z-H$XQl#Lv+ilQ5!h}&Q(gSqJUv@j?`q;$x_76f74kunkR_rH>Np#sx3)}g2>YZQeG
zdusVf6l=zyxdb`LtH#qP*RQeOw)lQ`Ex&52#^G3kmC-mCfoTZRFU_L!9uC}LhrcD2
zwV0`!9E`;A>px|l77FuX**F+eh6<o4WZrLra1`*1Jd}5iQbJb;2kb1(kr<SYMM1Ds
z(+yhV2^Pnb0oDvbJQdX1fKJ6^MH0C7?fQ%)keW)XmUnsHviKwB1peqcemsGaE(?GI
z@)eU6eqi@O&IQ*6>9MbBIxWiE8_0FFbJOa@1n?z)%OV0P3;4lF3cj~V0;zH?m!VKL
zc9wr!hssaBMn%$+bHE=|ce0qM@H1a>%F8iPO7QahH9+X)Iq!Kygy3o4=iO`{9j;Rp
zrYx$WLVZe~BUMxR#m=%=KwiQR1B9;2G26mc6?SMk*L%BJ(B00zIrnyyvi~MQdNgOV
ztZO{Y^qfnTVbWYZhYl#jfBp<Ta~5Jo6Rgw>;;%l(p~n{Tu@E?lN<t_YNIHRUT!$^a
zJ?w11NxHM0v!+Qjo?_{jhsYEu1lt?XEAFE;RmxL+T^!A{Q?sR-TMS|QKWDDh%V9Ij
zgpzVrtbUTFVnqgQ=ZBbMD`|+vSZnpt*PY?G>u?Ui4FLv%Dbi<&qB18Or6W0pS5`m4
zSH&Ddwt#~zJQ|C!S;BnVBI0C&lUgWXnEYvmIAj<csGfWG79F<hHMSB8hq-8mnXKvH
zOExc`!F$7DhV9Gi7hvDINfrsQID|s94Yz(oLV%u5aO|Ma^SO~$gI4^osh+5!Fj-M~
zKoLw5DseN!ctxYXmn=Kj!o;@gv}G->_#Rh%pKE*H95|N(4Qux>U(?xUhMBD!sD>G|
zPE8Arv2-a!W03ctt0VB*&VrYRoJ+>FIpH{L+qHo<4M0_?PL=R@X+;3k3{VwN)Sw^h
z1_%{20m(E(6X55;_rc4Pb{$rAw$lWh8_4p$V?10wfq9V_Q*@IDRh3DKAT9(kp`sR!
vEK5pkeA;}t>U&(t=lIceIJ5kbU=#cYq}!}^Q*#`X00000NkvXXu0mjfDh+5e
new file mode 100644
index 0000000000000000000000000000000000000000..c023ecdae077423f6a506f820160f47b5f72f571
GIT binary patch
literal 2464
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
new file mode 100644
index 0000000000000000000000000000000000000000..94053ac8553747047b6988707544ce07aba48fb4
GIT binary patch
literal 2908
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
new file mode 100644
index 0000000000000000000000000000000000000000..4a1a30c0c0e566b123cea88066c32b9fd1c10df9
GIT binary patch
literal 8787
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
BOTYjC
new file mode 100644
index 0000000000000000000000000000000000000000..5b35a72829d9820c873a4357735f81d57d4ef623
GIT binary patch
literal 1047
zc$@(j1nB#TP)<h;3K|Lk000e1NJLTq000#L0012b1^@s6MMNk200004b3#c}2nYxW
zd<bNS00009a7bBm000XT000XT0n*)m`~Uy|6?8>dbVG7wVRUJ4ZXi@?ZDjy5G%q$U
zF*Bej{!ah^0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q18_-1
zK~zYIrIlT1TtyVef3r<@W`ngtj3PAYgNvUOi=t5JgAr-8RxQ<H715}OAVMB2SdmhS
z4}PHNQz<G)MMaDt5-ZwDZJ{>cQ>rM$D2R<8wc<w!ng47x$A_KW-fnj{QvYzdch1cG
z=A1J#=Q=YR2UY>MI_C~iP?S7yEwBuj1tuyX{K7&qvvI3y&dja{n2XUx>9HvN5hZJR
z-j34w-I&hIdVvpsAwa;LN~r|A*Ja)jU{xiAAKP`7oO5%)I$#_Kz`Mcw#lW*&paa0m
z9X)M)m{}Qk6SxDI2S$|Ag}}Bh@M<N5?@sfyNq4RWY|7vg@Otq6D6qwyT)S0Qw=<TC
z4W(38O3wp3vuQ{0e%`Q0viGeD3qmnGa6l=&1-y{0&js)MfqNb9L?@R!L+eqV4ScMW
zJ_Vl2J==r#D-7ERL~H?Qlm?=-H%j+s+X3KnU{oo+13Z!Kj|cB>1a5K8?a$+Wi_*nW
z+83quP2Zw430wh8Qa`KLwJiKo@ct@bM{e&*wc2JgTMbNM4C8o_dd{z`gmAbAxa5@J
zPe1hYO6lR?{R6<Oz<s`4_Dbn{;GDw2C}q~+67Wp-3{e7JQA!s8_W&n=O~L!iOQq88
z!nkSR!)7Z=Uqxv$O1{lqFFr4s*==T4%k^TPQW}cVXHhz@!RyKISzt*egcPM89B$Cs
zZ}F&7S{l5+8F(KU^5ybkV6AiRuVQFWFA&RfsT=D6Y-mI&Jp`-;jsvTKJ!aO|3jGA=
z1#SYK&Wm)A1K6mP0M-D%1J?li&8)vUEJ}S*`ZG#jM5&z5-q#)Sswh3!m}_P$%<Nds
z@wAyOD}qP!q}QUfD8omhG!~_aDD95Y)+i0+@i#>2c$C(e*+phHlfhF>Xs-5eWbmFS
zRoew0r4XfUQL060CQ5_Z<Eoi`X=W3yWx^t0JFq32_ENu&KU1#>D}W6^A8-)3s}jOY
z+pM?orV4BZ)&s@=(cc-i6Bw(6(5@VIS5C>1!X~ZxFY`*>I(sV>1O6$PYX2L0rs^p+
z^8LLOr~-q)QtF%1(4$cr27U#;1*XhwI!Dx$%dic=R$%2BICc!!1w2^^p#~?zzr7CZ
z_}A>Fe&BB4+*3Tw-mV0Ofy;m@#&R5I0ZR&t&jJxRN<I8<fJ4AXl@L;c^)GlT80X{8
RuiXFu002ovPDHLkV1lo_*TMh*
new file mode 100644
index 0000000000000000000000000000000000000000..ff0f369cdd064675a902a931c896672aaf916658
GIT binary patch
literal 734
zc$@*=0wMj0P)<h;3K|Lk000e1NJLTq000vJ000~a1^@s6g9d~d00004b3#c}2nYxW
zd<bNS00009a7bBm000XT000XT0n*)m`~Uy|6?8>dbVG7wVRUJ4ZXi@?ZDjy5G%q$U
zF*Bej{!ah^0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q0yjxS
zK~zYIm6Shd6j2bye|wzxo&o<frqG;NDB6S+1|*H3A|Z`7CRQm^rnJx$!NN)i>8&h+
zgcJ&?LJ%wz1A>j9XdxJzB#8eY^MyNIi<?b0ce}Z}fn}L_-}k+lVctNAnKWe5qDkLP
zO8viR(oh+vOlZoahKsa*4U?vdcu9fK72pL>IpDs3z||PS%Y3ki@SrfB?z_9<xbn<Q
zIt*-g$SN-%V+cECne}%mlqJ%i53~{w5Nd008@}5t@TMJT6_cta-8E^jd*MAZY0&xA
zDzF6H1a1JgffMD_q&33?cnn+vMykM=A5?*3z?X8dwo=bJ4`8eUEO#!ZD_gDr<G_{&
z8a)bR_$^?(5<_UXa|qaI6-<gpA`{wh-c}5uk&VVWa3+RO2UhZow0tC19A9((?wq{>
zPWgDu0QC;#)qxqupLYJP*aGkun2jO4114y`(IVRhCLA~GyoG%TljeP2O}k$+Y0jkg
zCT;qE&ZL^3Pdk3T?K+d9X=lv=k4)+-O3S1^KTl0sGwDcn*1Cd@0#9hZhz;N=@EX_z
zP68vq9Z32ieGW{<5Pp}mV^?(4q*asZEi1e3@zEk)=@7Z-0Pr;zs>Kl2%kZ66(4P)|
zPhve;HSd^o9Jm0S0|v;gqlAQ%^u9?yXiofR;A0Ho=N_ghatpWzT%toCTPy|M0uN&d
z&$2Qnf#Dv7vSfyxzehIdGH@NZ2%M++<|567nb|MEfN#Jj-~+H4LwE!5A1YriKdi`M
Q82|tP07*qoM6N<$f@$zE$p8QV
new file mode 100644
index 0000000000000000000000000000000000000000..58c3c5ef3d051c447175d4e426ad9da6a5a7cfcb
GIT binary patch
literal 861
zc$@)U1ETziP)<h;3K|Lk000e1NJLTq000;O000yS1^@s6m$m(a00004b3#c}2nYxW
zd<bNS00009a7bBm000XT000XT0n*)m`~Uy|6?8>dbVG7wVRUJ4ZXi@?ZDjy5G%q$U
zF*Bej{!ah^0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q0=7v+
zK~y-6os~(5lt&cDfA7=u*FA|E!MTi*n2Q%tPhu3o1rZcMya>rHL?Y%YA|CXTarEYb
zptxKF^<;<(xRK-_CYnG93L|JhP!#vkxYVn*+rNjdk#e-#(Rcakt-tr`E2@xmNzye*
zljtD9{k!0PGq^Y0<Jl1W(@yb&QUC@_1kOpC(x&)4U=J`BST59q@#Am+Na{{gNYVpI
zGlmrJ4(_*uyMp_nWLpv3FAWQjK`tc7V@b0!z%Qw|g8S-Z`!eYh-dDQ-FtdBWLf}te
zG;mtd{NVmAur!Omni{$e1YqW{0Kt8X$7nAajb*^^Kn*xiRw^%nzq0uI0A0135^Qq2
z!ji@T6z=hJU;r3sHk!9%z5Xk345*md{<2cpnL!2y3mA4Ec;^;LnhV^JG^-GrO6w$n
zfnKWDW4r(y20k&fePyMxH%<1sW1%O&_%;Jv1V#c&3gC-3TrE^@jP-wjgFs<syQ^h+
z1elXWKBu*ndFRU|%`~%zz<FSLLF=c!Jto@dG4=zyl4)zTEN=z(GU@fyWiG3LZ_@fQ
z&{F`FHe&+xdW_eBElKaImgSnv-xw1A2&krY6I!QefX>qAG2R9GlKzvV&A>C@{~@uX
zfc~`p3b<JSH{JsP*yJ%j0oEmbZM7^5;7}f9W($BFl4`(g;13J#qk(_ZG`VyE-LI1|
zgr-%?at^RPnfC!J&8(RxN?HJ%0j9NWIk<lo-2cn22?h5>slX4Cn(1meAZf(Vd`Uf>
zH>CynI=DA7!1n;|aa^<6T%SRXO6qi2Izl#NfNjaP%st+bv{X_(K~75Q`WQeF+)pP!
ze+XU#k4J+0&j6AZOM0FlzeyVPF_7-yel0<+r0>E(zohw+o+iktJl8$|G7(q-i~%mz
ns?|NYKRr~(fxpdc@u2+`NX+Ca%_PBT00000NkvXXu0mjf-}`<7
new file mode 100644
index 0000000000000000000000000000000000000000..dc4da4fe74cc30d632cd28f96174ab172fd2e245
GIT binary patch
literal 622
zc$@)l0+IcRP)<h;3K|Lk000e1NJLTq000*N000vR1^@s6d%Kpl00004b3#c}2nYxW
zd<bNS00009a7bBm000XT000XT0n*)m`~Uy|6?8>dbVG7wVRUJ4ZXi@?ZDjy5G%q$U
zF*Bej{!ah^0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q0mn&1
zK~y-6rIf#q4N(||pL30vD>vDYUE9cQ)(Wy@2?g6+r9wd>N}ZmDkmV0hXcTIyRnlmM
zf{5(KkHpFqHV8sk!G7;1%TeqnId|MKW4+1bJm<XUd(W4dlYtsCX|G8yOo}GGHfc+p
zx=<sy4NL>;fn&fSV5ynsN9r8#x8TgAJKpiEuZ@|sXwpDceWSvk1SXtk0GfIJ7?=n4
zuQ=SK-N4yoshjXDu%{|KGieMM?BiVmRweUK2|ok2^$UzK4g;rv3mI?)*x9>-exLeF
zfp?TNybd@4%r$_Gf7t!+(1C=%0vie)uZ}Seh7g_tkAO}C7%J(YsKX|0b^Z>t3jP#u
z&iNiNT6J5B8uxJt$O_&YpzZt_X#H#WoR0&53f?B*t@9A@J_8njwKamD19z7(<Pg6V
z{NunH=Y7Dfh8NY*)n=amT*lY}KBQ&{;Z+Es8)F;?HUrl);IvPA_5x?<z5j~|w}F=>
zO>}{yz|GP&O*-iRl;6+A#Cu}WWNERh^n*6@{04A2SsL-+92f=euQ=Rw5_ssmYr!l4
z9pDFWyDGd=CXJXh@2}>(Ne@iA_TRzD0UeXx`2inI+Fqyb7iMF@9wFe*z5oCK07*qo
IM6N<$g8JwS0RR91
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js
@@ -0,0 +1,28 @@
+/**
+ * @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);
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/content/shared/libs/sdk.js
@@ -0,0 +1,18115 @@
+/**
+ * @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(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)
+
+    // 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',
+    // The URL to use for logging
+    loggingURL: 'https://hlg.tokbox.com/prod',
+    // The anvil API URL
+    apiURL: 'https://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',
+    // The anvil API URL to use if we're using SSL
+    apiURLSSL: 'https://anvil.opentok.com',
+
+    minimumVersion: {
+      firefox: parseFloat('26'),
+      chrome: parseFloat('32')
+    }
+  };
+
+})(window);
+/**
+ * @license  Common JS Helpers on OpenTok 0.2.0 1f056b9 master
+ * http://www.tokbox.com/
+ *
+ * Copyright (c) 2014 TokBox, Inc.
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ * Date: May 19 04:04:43 2014
+ *
+ */
+
+// OT Helper Methods
+//
+// helpers.js                           <- the root file
+// helpers/lib/{helper topic}.js        <- specialised helpers for specific tasks/topics
+//                                          (i.e. video, dom, etc)
+//
+// @example Getting a DOM element by it's id
+//  var element = OTHelpers('domId');
+//
+// @example Testing for web socket support
+//  if (OT.supportsWebSockets()) {
+//      // do some stuff with websockets
+//  }
+//
+
+/*jshint browser:true, smarttabs:true*/
+
+!(function(window, undefined) {
+
+
+  var OTHelpers = function(domId) {
+    return document.getElementById(domId);
+  };
+
+  var previousOTHelpers = window.OTHelpers;
+
+  window.OTHelpers = OTHelpers;
+
+  OTHelpers.keys = Object.keys || function(object) {
+    var keys = [], hasOwnProperty = Object.prototype.hasOwnProperty;
+    for(var key in object) {
+      if(hasOwnProperty.call(object, key)) {
+        keys.push(key);
+      }
+    }
+    return keys;
+  };
+
+  var _each = Array.prototype.forEach || function(iter, ctx) {
+    for(var idx = 0, count = this.length || 0; idx < count; ++idx) {
+      if(idx in this) {
+        iter.call(ctx, this[idx], idx);
+      }
+    }
+  };
+
+  OTHelpers.forEach = function(array, iter, ctx) {
+    return _each.call(array, iter, ctx);
+  };
+
+  var _map = Array.prototype.map || function(iter, ctx) {
+    var collect = [];
+    _each.call(this, function(item, idx) {
+      collect.push(iter.call(ctx, item, idx));
+    });
+    return collect;
+  };
+
+  OTHelpers.map = function(array, iter) {
+    return _map.call(array, iter);
+  };
+
+  var _filter = Array.prototype.filter || function(iter, ctx) {
+    var collect = [];
+    _each.call(this, function(item, idx) {
+      if(iter.call(ctx, item, idx)) {
+        collect.push(item);
+      }
+    });
+    return collect;
+  };
+
+  OTHelpers.filter = function(array, iter, ctx) {
+    return _filter.call(array, iter, ctx);
+  };
+
+  var _some = Array.prototype.some || function(iter, ctx) {
+    var any = false;
+    for(var idx = 0, count = this.length || 0; idx < count; ++idx) {
+      if(idx in this) {
+        if(iter.call(ctx, this[idx], idx)) {
+          any = true;
+          break;
+        }
+      }
+    }
+    return any;
+  };
+
+  OTHelpers.some = function(array, iter, ctx) {
+    return _some.call(array, iter, ctx);
+  };
+
+  var _indexOf = Array.prototype.indexOf || function(searchElement, fromIndex) {
+    var i,
+        pivot = (fromIndex) ? fromIndex : 0,
+        length;
+
+    if (!this) {
+      throw new TypeError();
+    }
+
+    length = this.length;
+
+    if (length === 0 || pivot >= length) {
+      return -1;
+    }
+
+    if (pivot < 0) {
+      pivot = length - Math.abs(pivot);
+    }
+
+    for (i = pivot; i < length; i++) {
+      if (this[i] === searchElement) {
+        return i;
+      }
+    }
+    return -1;
+  };
+
+  OTHelpers.arrayIndexOf = function(array, searchElement, fromIndex) {
+    return _indexOf.call(array, searchElement, fromIndex);
+  };
+
+  var _bind = Function.prototype.bind || function() {
+    var args = Array.prototype.slice.call(arguments),
+        ctx = args.shift(),
+        fn = this;
+    return function() {
+      return fn.apply(ctx, args.concat(Array.prototype.slice.call(arguments)));
+    };
+  };
+
+  OTHelpers.bind = function() {
+    var args = Array.prototype.slice.call(arguments),
+        fn = args.shift();
+    return _bind.apply(fn, args);
+  };
+
+  var _trim = String.prototype.trim || function() {
+    return this.replace(/^\s+|\s+$/g, '');
+  };
+
+  OTHelpers.trim = function(str) {
+    return _trim.call(str);
+  };
+
+  OTHelpers.noConflict = function() {
+    OTHelpers.noConflict = function() {
+      return OTHelpers;
+    };
+    window.OTHelpers = previousOTHelpers;
+    return OTHelpers;
+  };
+
+  OTHelpers.isNone = function(obj) {
+    return obj === undefined || obj === null;
+  };
+
+  OTHelpers.isObject = function(obj) {
+    return obj === Object(obj);
+  };
+
+  OTHelpers.isFunction = function(obj) {
+    return !!obj && (obj.toString().indexOf('()') !== -1 ||
+      Object.prototype.toString.call(obj) === '[object Function]');
+  };
+
+  OTHelpers.isArray = OTHelpers.isFunction(Array.isArray) && Array.isArray ||
+    function (vArg) {
+      return Object.prototype.toString.call(vArg) === '[object Array]';
+    };
+
+  OTHelpers.isEmpty = function(obj) {
+    if (obj === null || obj === undefined) return true;
+    if (OTHelpers.isArray(obj) || typeof(obj) === 'string') return obj.length === 0;
+
+    // Objects without enumerable owned properties are empty.
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) return false;
+    }
+
+    return true;
+  };
+
+// Extend a target object with the properties from one or
+// more source objects
+//
+// @example:
+//    dest = OTHelpers.extend(dest, source1, source2, source3);
+//
+  OTHelpers.extend = function(/* dest, source1[, source2, ..., , sourceN]*/) {
+    var sources = Array.prototype.slice.call(arguments),
+        dest = sources.shift();
+
+    OTHelpers.forEach(sources, function(source) {
+      for (var key in source) {
+        dest[key] = source[key];
+      }
+    });
+
+    return dest;
+  };
+
+// Ensures that the target object contains certain defaults.
+//
+// @example
+//   var options = OTHelpers.defaults(options, {
+//     loading: true     // loading by default
+//   });
+//
+  OTHelpers.defaults = function(/* dest, defaults1[, defaults2, ..., , defaultsN]*/) {
+    var sources = Array.prototype.slice.call(arguments),
+        dest = sources.shift();
+
+    OTHelpers.forEach(sources, function(source) {
+      for (var key in source) {
+        if (dest[key] === void 0) dest[key] = source[key];
+      }
+    });
+
+    return dest;
+  };
+
+  OTHelpers.clone = function(obj) {
+    if (!OTHelpers.isObject(obj)) return obj;
+    return OTHelpers.isArray(obj) ? obj.slice() : OTHelpers.extend({}, obj);
+  };
+
+
+
+// Handy do nothing function
+  OTHelpers.noop = function() {};
+
+// Returns true if the client supports WebSockets, false otherwise.
+  OTHelpers.supportsWebSockets = function() {
+    return 'WebSocket' in window;
+  };
+
+// Returns the number of millisceonds since the the UNIX epoch, this is functionally
+// equivalent to executing new Date().getTime().
+//
+// Where available, we use 'performance.now' which is more accurate and reliable,
+// otherwise we default to new Date().getTime().
+  OTHelpers.now = (function() {
+    var performance = window.performance || {},
+        navigationStart,
+        now =  performance.now       ||
+               performance.mozNow    ||
+               performance.msNow     ||
+               performance.oNow      ||
+               performance.webkitNow;
+
+    if (now) {
+      now = OTHelpers.bind(now, performance);
+      navigationStart = performance.timing.navigationStart;
+
+      return  function() { return navigationStart + now(); };
+    } else {
+      return function() { return new Date().getTime(); };
+    }
+  })();
+
+  var _browser = function() {
+    var userAgent = window.navigator.userAgent.toLowerCase(),
+        appName = window.navigator.appName,
+        navigatorVendor,
+        browser = 'unknown',
+        version = -1;
+
+    if (userAgent.indexOf('opera') > -1 || userAgent.indexOf('opr') > -1) {
+      browser = 'Opera';
+
+      if (/opr\/([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+
+    } else if (userAgent.indexOf('firefox') > -1)   {
+      browser = 'Firefox';
+
+      if (/firefox\/([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+
+    } else if (appName === 'Microsoft Internet Explorer') {
+      // IE 10 and below
+      browser = 'IE';
+
+      if (/msie ([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+
+    } else if (appName === 'Netscape' && userAgent.indexOf('trident') > -1) {
+      // IE 11+
+
+      browser = 'IE';
+
+      if (/trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+
+    } else if (userAgent.indexOf('chrome') > -1) {
+      browser = 'Chrome';
+
+      if (/chrome\/([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+
+    } else if ((navigatorVendor = window.navigator.vendor) &&
+      navigatorVendor.toLowerCase().indexOf('apple') > -1) {
+      browser = 'Safari';
+
+      if (/version\/([0-9]{1,}[\.0-9]{0,})/.exec(userAgent) !== null) {
+        version = parseFloat( RegExp.$1 );
+      }
+    }
+
+    return {
+      browser: browser,
+      version: version,
+      iframeNeedsLoad: userAgent.indexOf('webkit') < 0
+    };
+  }();
+
+  OTHelpers.browser = function() {
+    return _browser.browser;
+  };
+
+  OTHelpers.browserVersion = function() {
+    return _browser;
+  };
+
+
+  OTHelpers.canDefineProperty = true;
+
+  try {
+    Object.defineProperty({}, 'x', {});
+  } catch (err) {
+    OTHelpers.canDefineProperty = false;
+  }
+
+// A helper for defining a number of getters at once.
+//
+// @example: from inside an object
+//   OTHelpers.defineGetters(this, {
+//     apiKey: function() { return _apiKey; },
+//     token: function() { return _token; },
+//     connected: function() { return this.is('connected'); },
+//     capabilities: function() { return _socket.capabilities; },
+//     sessionId: function() { return _sessionId; },
+//     id: function() { return _sessionId; }
+//   });
+//
+  OTHelpers.defineGetters = function(self, getters, enumerable) {
+    var propsDefinition = {};
+
+    if (enumerable === void 0) enumerable = false;
+
+    for (var key in getters) {
+      propsDefinition[key] = {
+        get: getters[key],
+        enumerable: enumerable
+      };
+    }
+
+    OTHelpers.defineProperties(self, propsDefinition);
+  };
+
+  var generatePropertyFunction = function(object, getter, setter) {
+    if(getter && !setter) {
+      return function() {
+        return getter.call(object);
+      };
+    } else if(getter && setter) {
+      return function(value) {
+        if(value !== void 0) {
+          setter.call(object, value);
+        }
+        return getter.call(object);
+      };
+    } else {
+      return function(value) {
+        if(value !== void 0) {
+          setter.call(object, value);
+        }
+      };
+    }
+  };
+
+  OTHelpers.defineProperties = function(object, getterSetters) {
+    for (var key in getterSetters) {
+      object[key] = generatePropertyFunction(object, getterSetters[key].get,
+        getterSetters[key].set);
+    }
+  };
+
+
+// Polyfill Object.create for IE8
+//
+// See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
+//
+  if (!Object.create) {
+    Object.create = function (o) {
+      if (arguments.length > 1) {
+        throw new Error('Object.create implementation only accepts the first parameter.');
+      }
+      function F() {}
+      F.prototype = o;
+      return new F();
+    };
+  }
+
+  OTHelpers.setCookie = function(key, value) {
+    try {
+      localStorage.setItem(key, value);
+    } catch (err) {
+      // Store in browser cookie
+      var date = new Date();
+      date.setTime(date.getTime()+(365*24*60*60*1000));
+      var expires = '; expires=' + date.toGMTString();
+      document.cookie = key + '=' + value + expires + '; path=/';
+    }
+  };
+
+  OTHelpers.getCookie = function(key) {
+    var value;
+
+    try {
+      value = localStorage.getItem('opentok_client_id');
+      return value;
+    } catch (err) {
+      // Check browser cookies
+      var nameEQ = key + '=';
+      var ca = document.cookie.split(';');
+      for(var i=0;i < ca.length;i++) {
+        var c = ca[i];
+        while (c.charAt(0) === ' ') {
+          c = c.substring(1,c.length);
+        }
+        if (c.indexOf(nameEQ) === 0) {
+          value = c.substring(nameEQ.length,c.length);
+        }
+      }
+
+      if (value) {
+        return value;
+      }
+    }
+
+    return null;
+  };
+
+
+// These next bits are included from Underscore.js. The original copyright
+// notice is below.
+//
+// http://underscorejs.org
+// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc.
+// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+
+  // Invert the keys and values of an object. The values must be serializable.
+  OTHelpers.invert = function(obj) {
+    var result = {};
+    for (var key in obj) if (obj.hasOwnProperty(key)) result[obj[key]] = key;
+    return result;
+  };
+
+
+  // List of HTML entities for escaping.
+  var entityMap = {
+    escape: {
+      '&':  '&amp;',
+      '<':  '&lt;',
+      '>':  '&gt;',
+      '"':  '&quot;',
+      '\'': '&#x27;',
+      '/':  '&#x2F;'
+    }
+  };
+
+  entityMap.unescape = OTHelpers.invert(entityMap.escape);
+
+  // Regexes containing the keys and values listed immediately above.
+  var entityRegexes = {
+    escape:   new RegExp('[' + OTHelpers.keys(entityMap.escape).join('') + ']', 'g'),
+    unescape: new RegExp('(' + OTHelpers.keys(entityMap.unescape).join('|') + ')', 'g')
+  };
+
+  // Functions for escaping and unescaping strings to/from HTML interpolation.
+  OTHelpers.forEach(['escape', 'unescape'], function(method) {
+    OTHelpers[method] = function(string) {
+      if (string === null || string === undefined) return '';
+      return ('' + string).replace(entityRegexes[method], function(match) {
+        return entityMap[method][match];
+      });
+    };
+  });
+
+// By default, Underscore uses ERB-style template delimiters, change the
+// following template settings to use alternative delimiters.
+  OTHelpers.templateSettings = {
+    evaluate    : /<%([\s\S]+?)%>/g,
+    interpolate : /<%=([\s\S]+?)%>/g,
+    escape      : /<%-([\s\S]+?)%>/g
+  };
+
+// When customizing `templateSettings`, if you don't want to define an
+// interpolation, evaluation or escaping regex, we need one that is
+// guaranteed not to match.
+  var noMatch = /(.)^/;
+
+// Certain characters need to be escaped so that they can be put into a
+// string literal.
+  var escapes = {
+    '\'':     '\'',
+    '\\':     '\\',
+    '\r':     'r',
+    '\n':     'n',
+    '\t':     't',
+    '\u2028': 'u2028',
+    '\u2029': 'u2029'
+  };
+
+  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+
+// JavaScript micro-templating, similar to John Resig's implementation.
+// Underscore templating handles arbitrary delimiters, preserves whitespace,
+// and correctly escapes quotes within interpolated code.
+  OTHelpers.template = function(text, data, settings) {
+    var render;
+    settings = OTHelpers.defaults({}, settings, OTHelpers.templateSettings);
+
+    // Combine delimiters into one regular expression via alternation.
+    var matcher = new RegExp([
+      (settings.escape || noMatch).source,
+      (settings.interpolate || noMatch).source,
+      (settings.evaluate || noMatch).source
+    ].join('|') + '|$', 'g');
+
+    // Compile the template source, escaping string literals appropriately.
+    var index = 0;
+    var source = '__p+=\'';
+    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+      source += text.slice(index, offset)
+        .replace(escaper, function(match) { return '\\' + escapes[match]; });
+
+      if (escape) {
+        source += '\'+\n((__t=(' + escape + '))==null?\'\':OTHelpers.escape(__t))+\n\'';
+      }
+      if (interpolate) {
+        source += '\'+\n((__t=(' + interpolate + '))==null?\'\':__t)+\n\'';
+      }
+      if (evaluate) {
+        source += '\';\n' + evaluate + '\n__p+=\'';
+      }
+      index = offset + match.length;
+      return match;
+    });
+    source += '\';\n';
+
+    // If a variable is not specified, place data values in local scope.
+    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+    source = 'var __t,__p=\'\',__j=Array.prototype.join,' +
+      'print=function(){__p+=__j.call(arguments,\'\');};\n' +
+      source + 'return __p;\n';
+
+    try {
+      // evil is necessary for the new Function line
+      /*jshint evil:true */
+      render = new Function(settings.variable || 'obj', source);
+    } catch (e) {
+      e.source = source;
+      throw e;
+    }
+
+    if (data) return render(data);
+    var template = function(data) {
+      return render.call(this, data);
+    };
+
+    // Provide the compiled function source as a convenience for precompilation.
+    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+
+    return template;
+  };
+
+})(window);
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../../helpers.js')
+
+(function(window, OTHelpers, undefined) {
+
+  OTHelpers.statable = function(self, possibleStates, initialState, stateChanged,
+    stateChangedFailed) {
+    var previousState,
+        currentState = self.currentState = initialState;
+
+    var setState = function(state) {
+      if (currentState !== state) {
+        if (OTHelpers.arrayIndexOf(possibleStates, state) === -1) {
+          if (stateChangedFailed && OTHelpers.isFunction(stateChangedFailed)) {
+            stateChangedFailed('invalidState', state);
+          }
+          return;
+        }
+
+        self.previousState = previousState = currentState;
+        self.currentState = currentState = state;
+        if (stateChanged && OTHelpers.isFunction(stateChanged)) stateChanged(state, previousState);
+      }
+    };
+
+
+    // Returns a number of states and returns true if the current state
+    // is any of them.
+    //
+    // @example
+    // if (this.is('connecting', 'connected')) {
+    //   // do some stuff
+    // }
+    //
+    self.is = function (/* state0:String, state1:String, ..., stateN:String */) {
+      return OTHelpers.arrayIndexOf(arguments, currentState) !== -1;
+    };
+
+
+    // Returns a number of states and returns true if the current state
+    // is none of them.
+    //
+    // @example
+    // if (this.isNot('connecting', 'connected')) {
+    //   // do some stuff
+    // }
+    //
+    self.isNot = function (/* state0:String, state1:String, ..., stateN:String */) {
+      return OTHelpers.arrayIndexOf(arguments, currentState) === -1;
+    };
+
+    return setState;
+  };
+
+})(window, window.OTHelpers);
+
+/*!
+ *  This is a modified version of Robert Kieffer awesome uuid.js library.
+ *  The only modifications we've made are to remove the Node.js specific
+ *  parts of the code and the UUID version 1 generator (which we don't
+ *  use). The original copyright notice is below.
+ *
+ *     node-uuid/uuid.js
+ *
+ *     Copyright (c) 2010 Robert Kieffer
+ *     Dual licensed under the MIT and GPL licenses.
+ *     Documentation and details at https://github.com/broofa/node-uuid
+ */
+// tb_require('../helpers.js')
+
+/*global crypto:true, Uint32Array:true, Buffer:true */
+/*jshint browser:true, smarttabs:true*/
+
+(function(window, OTHelpers, undefined) {
+
+  // Unique ID creation requires a high quality random # generator, but
+  // Math.random() does not guarantee "cryptographic quality".  So we feature
+  // detect for more robust APIs, normalizing each method to return 128-bits
+  // (16 bytes) of random data.
+  var mathRNG, whatwgRNG;
+
+  // Math.random()-based RNG.  All platforms, very fast, unknown quality
+  var _rndBytes = new Array(16);
+  mathRNG = function() {
+    var r, b = _rndBytes, i = 0;
+
+    for (i = 0; i < 16; i++) {
+      if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
+      b[i] = r >>> ((i & 0x03) << 3) & 0xff;
+    }
+
+    return b;
+  };
+
+  // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
+  // WebKit only (currently), moderately fast, high quality
+  if (window.crypto && crypto.getRandomValues) {
+    var _rnds = new Uint32Array(4);
+    whatwgRNG = function() {
+      crypto.getRandomValues(_rnds);
+
+      for (var c = 0 ; c < 16; c++) {
+        _rndBytes[c] = _rnds[c >> 2] >>> ((c & 0x03) * 8) & 0xff;
+      }
+      return _rndBytes;
+    };
+  }
+
+  // Select RNG with best quality
+  var _rng = whatwgRNG || mathRNG;
+
+  // Buffer class to use
+  var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
+
+  // Maps for number <-> hex string conversion
+  var _byteToHex = [];
+  var _hexToByte = {};
+  for (var i = 0; i < 256; i++) {
+    _byteToHex[i] = (i + 0x100).toString(16).substr(1);
+    _hexToByte[_byteToHex[i]] = i;
+  }
+
+  // **`parse()` - Parse a UUID into it's component bytes**
+  function parse(s, buf, offset) {
+    var i = (buf && offset) || 0, ii = 0;
+
+    buf = buf || [];
+    s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
+      if (ii < 16) { // Don't overflow!
+        buf[i + ii++] = _hexToByte[oct];
+      }
+    });
+
+    // Zero out remaining bytes if string was short
+    while (ii < 16) {
+      buf[i + ii++] = 0;
+    }
+
+    return buf;
+  }
+
+  // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
+  function unparse(buf, offset) {
+    var i = offset || 0, bth = _byteToHex;
+    return  bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] + '-' +
+            bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]] +
+            bth[buf[i++]] + bth[buf[i++]];
+  }
+
+  // **`v4()` - Generate random UUID**
+
+  // See https://github.com/broofa/node-uuid for API details
+  function v4(options, buf, offset) {
+    // Deprecated - 'format' argument, as supported in v1.2
+    var i = buf && offset || 0;
+
+    if (typeof(options) == 'string') {
+      buf = options == 'binary' ? new BufferClass(16) : null;
+      options = null;
+    }
+    options = options || {};
+
+    var rnds = options.random || (options.rng || _rng)();
+
+    // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
+    rnds[6] = (rnds[6] & 0x0f) | 0x40;
+    rnds[8] = (rnds[8] & 0x3f) | 0x80;
+
+    // Copy bytes to buffer, if provided
+    if (buf) {
+      for (var ii = 0; ii < 16; ii++) {
+        buf[i + ii] = rnds[ii];
+      }
+    }
+
+    return buf || unparse(rnds);
+  }
+
+  // Export public API
+  var uuid = v4;
+  uuid.v4 = v4;
+  uuid.parse = parse;
+  uuid.unparse = unparse;
+  uuid.BufferClass = BufferClass;
+
+  // Export RNG options
+  uuid.mathRNG = mathRNG;
+  uuid.whatwgRNG = whatwgRNG;
+
+  OTHelpers.uuid = uuid;
+
+}(window, window.OTHelpers));
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+
+(function(window, OTHelpers, undefined) {
+
+OTHelpers.useLogHelpers = function(on){
+
+    // Log levels for OTLog.setLogLevel
+    on.DEBUG    = 5;
+    on.LOG      = 4;
+    on.INFO     = 3;
+    on.WARN     = 2;
+    on.ERROR    = 1;
+    on.NONE     = 0;
+
+    var _logLevel = on.NONE,
+        _logs = [],
+        _canApplyConsole = true;
+
+    try {
+        Function.prototype.bind.call(window.console.log, window.console);
+    } catch (err) {
+        _canApplyConsole = false;
+    }
+
+    // Some objects can't be logged in the console, mostly these are certain
+    // types of native objects that are exposed to JS. This is only really a
+    // problem with IE, hence only the IE version does anything.
+    var makeLogArgumentsSafe = function(args) { return args; };
+
+    if (OTHelpers.browser() === 'IE') {
+        makeLogArgumentsSafe = function(args) {
+            return [toDebugString(Array.prototype.slice.apply(args))];
+        };
+    }
+
+    // Generates a logging method for a particular method and log level.
+    //
+    // Attempts to handle the following cases:
+    // * the desired log method doesn't exist, call fallback (if available) instead
+    // * the console functionality isn't available because the developer tools (in IE)
+    // aren't open, call fallback (if available)
+    // * attempt to deal with weird IE hosted logging methods as best we can.
+    //
+    function generateLoggingMethod(method, level, fallback) {
+        return function() {
+            if (on.shouldLog(level)) {
+                var cons = window.console,
+                    args = makeLogArgumentsSafe(arguments);
+
+                // In IE, window.console may not exist if the developer tools aren't open
+                // This also means that cons and cons[method] can appear at any moment
+                // hence why we retest this every time.
+                if (cons && cons[method]) {
+                    // the desired console method isn't a real object, which means
+                    // that we can't use apply on it. We force it to be a real object
+                    // using Function.bind, assuming that's available.
+                    if (cons[method].apply || _canApplyConsole) {
+                        if (!cons[method].apply) {
+                            cons[method] = Function.prototype.bind.call(cons[method], cons);
+                        }
+
+                        cons[method].apply(cons, args);
+                    }
+                    else {
+                        // This isn't the same result as the above, but it's better
+                        // than nothing.
+                        cons[method](args);
+                    }
+                }
+                else if (fallback) {
+                    fallback.apply(on, args);
+
+                    // Skip appendToLogs, we delegate entirely to the fallback
+                    return;
+                }
+
+                appendToLogs(method, makeLogArgumentsSafe(arguments));
+            }
+        };
+    }
+
+    on.log = generateLoggingMethod('log', on.LOG);
+
+    // Generate debug, info, warn, and error logging methods, these all fallback to on.log
+    on.debug = generateLoggingMethod('debug', on.DEBUG, on.log);
+    on.info = generateLoggingMethod('info', on.INFO, on.log);
+    on.warn = generateLoggingMethod('warn', on.WARN, on.log);
+    on.error = generateLoggingMethod('error', on.ERROR, on.log);
+
+
+    on.setLogLevel = function(level) {
+        _logLevel = typeof(level) === 'number' ? level : 0;
+        on.debug("TB.setLogLevel(" + _logLevel + ")");
+        return _logLevel;
+    };
+
+    on.getLogs = function() {
+        return _logs;
+    };
+
+    // Determine if the level is visible given the current logLevel.
+    on.shouldLog = function(level) {
+        return _logLevel >= level;
+    };
+
+    // Format the current time nicely for logging. Returns the current
+    // local time.
+    function formatDateStamp() {
+        var now = new Date();
+        return now.toLocaleTimeString() + now.getMilliseconds();
+    }
+
+    function toJson(object) {
+        try {
+            return JSON.stringify(object);
+        } catch(e) {
+            return object.toString();
+        }
+    }
+
+    function toDebugString(object) {
+        var components = [];
+
+        if (typeof(object) === 'undefined') {
+            // noop
+        }
+        else if (object === null) {
+            components.push('NULL');
+        }
+        else if (OTHelpers.isArray(object)) {
+            for (var i=0; i<object.length; ++i) {
+                components.push(toJson(object[i]));
+            }
+        }
+        else if (OTHelpers.isObject(object)) {
+            for (var key in object) {
+                var stringValue;
+
+                if (!OTHelpers.isFunction(object[key])) {
+                    stringValue = toJson(object[key]);
+                }
+                else if (object.hasOwnProperty(key)) {
+                    stringValue = 'function ' + key + '()';
+                }
+
+                components.push(key + ': ' + stringValue);
+            }
+        }
+        else if (OTHelpers.isFunction(object)) {
+            try {
+                components.push(object.toString());
+            } catch(e) {
+                components.push('function()');
+            }
+        }
+        else  {
+            components.push(object.toString());
+        }
+
+        return components.join(", ");
+    }
+
+    // Append +args+ to logs, along with the current log level and the a date stamp.
+    function appendToLogs(level, args) {
+        if (!args) return;
+
+        var message = toDebugString(args);
+        if (message.length <= 2) return;
+
+        _logs.push(
+            [level, formatDateStamp(), message]
+        );
+    }
+};
+
+OTHelpers.useLogHelpers(OTHelpers);
+OTHelpers.setLogLevel(OTHelpers.ERROR);
+
+})(window, window.OTHelpers);
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+
+(function(window, OTHelpers, undefined) {
+
+OTHelpers.castToBoolean = function(value, defaultValue) {
+    if (value === undefined) return defaultValue;
+    return value === 'true' || value === true;
+};
+
+OTHelpers.roundFloat = function(value, places) {
+    return Number(value.toFixed(places));
+};
+
+})(window, window.OTHelpers);
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+// tb_require('../vendor/uuid.js')
+
+(function(window, OTHelpers, undefined) {
+
+  var timeouts = [],
+      messageName = 'OTHelpers.' + OTHelpers.uuid.v4() + '.zero-timeout';
+
+  var handleMessage = function(event) {
+    if (event.data === messageName) {
+      if(OTHelpers.isFunction(event.stopPropagation)) {
+        event.stopPropagation();
+      }
+      event.cancelBubble = true;
+      if (timeouts.length > 0) {
+        var args = timeouts.shift(),
+            fn = args.shift();
+
+        fn.apply(null, args);
+      }
+    }
+  };
+
+  if(window.addEventListener) {
+    window.addEventListener('message', handleMessage, true);
+  } else if(window.attachEvent) {
+    window.attachEvent('onmessage', handleMessage);
+  }
+
+  // Calls the function +fn+ asynchronously with the current execution.
+  // This is most commonly used to execute something straight after
+  // the current function.
+  //
+  // Any arguments in addition to +fn+ will be passed to +fn+ when it's
+  // called.
+  //
+  // You would use this inplace of setTimeout(fn, 0) type constructs. callAsync
+  // is preferable as it executes in a much more predictable time window,
+  // unlike setTimeout which could execute anywhere from 2ms to several thousand
+  // depending on the browser/context.
+  //
+  OTHelpers.callAsync = function (/* fn, [arg1, arg2, ..., argN] */) {
+    timeouts.push(Array.prototype.slice.call(arguments));
+    window.postMessage(messageName, '*');
+  };
+
+
+  // Wraps +handler+ in a function that will execute it asynchronously
+  // so that it doesn't interfere with it's exceution context if it raises
+  // an exception.
+  OTHelpers.createAsyncHandler = function(handler) {
+    return function() {
+      var args = Array.prototype.slice.call(arguments);
+
+      OTHelpers.callAsync(function() {
+        handler.apply(null, args);
+      });
+    };
+  };
+
+})(window, window.OTHelpers);
+
+/*jshint browser:true, smarttabs:true*/
+/*global jasmine:true*/
+
+// tb_require('../../helpers.js')
+// tb_require('../callbacks.js')
+
+(function(window, OTHelpers, undefined) {
+
+/**
+* This base class defines the <code>on</code>, <code>once</code>, and <code>off</code>
+* methods of objects that can dispatch events.
+*
+* @class EventDispatcher
+*/
+  OTHelpers.eventing = function(self, syncronous) {
+    var _events = {};
+
+
+    // Call the defaultAction, passing args
+    function executeDefaultAction(defaultAction, args) {
+      if (!defaultAction) return;
+
+      defaultAction.apply(null, args.slice());
+    }
+
+    // Execute each handler in +listeners+ with +args+.
+    //
+    // Each handler will be executed async. On completion the defaultAction
+    // handler will be executed with the args.
+    //
+    // @param [Array] listeners
+    //    An array of functions to execute. Each will be passed args.
+    //
+    // @param [Array] args
+    //    An array of arguments to execute each function in  +listeners+ with.
+    //
+    // @param [String] name
+    //    The name of this event.
+    //
+    // @param [Function, Null, Undefined] defaultAction
+    //    An optional function to execute after every other handler. This will execute even
+    //    if +listeners+ is empty. +defaultAction+ will be passed args as a normal
+    //    handler would.
+    //
+    // @return Undefined
+    //
+    function executeListenersAsyncronously(name, args, defaultAction) {
+      var listeners = _events[name];
+      if (!listeners || listeners.length === 0) return;
+
+      var listenerAcks = listeners.length;
+
+      OTHelpers.forEach(listeners, function(listener) { // , index
+        function filterHandlerAndContext(_listener) {
+          return _listener.context === listener.context && _listener.handler === listener.handler;
+        }
+
+        // We run this asynchronously so that it doesn't interfere with execution if an
+        // error happens
+        OTHelpers.callAsync(function() {
+          try {
+            // have to check if the listener has not been removed
+            if (_events[name] && OTHelpers.some(_events[name], filterHandlerAndContext)) {
+              (listener.closure || listener.handler).apply(listener.context || null, args);
+            }
+          }
+          finally {
+            listenerAcks--;
+
+            if (listenerAcks === 0) {
+              executeDefaultAction(defaultAction, args);
+            }
+          }
+        });
+      });
+    }
+
+
+    // This is identical to executeListenersAsyncronously except that handlers will
+    // be executed syncronously.
+    //
+    // On completion the defaultAction handler will be executed with the args.
+    //
+    // @param [Array] listeners
+    //    An array of functions to execute. Each will be passed args.
+    //
+    // @param [Array] args
+    //    An array of arguments to execute each function in  +listeners+ with.
+    //
+    // @param [String] name
+    //    The name of this event.
+    //
+    // @param [Function, Null, Undefined] defaultAction
+    //    An optional function to execute after every other handler. This will execute even
+    //    if +listeners+ is empty. +defaultAction+ will be passed args as a normal
+    //    handler would.
+    //
+    // @return Undefined
+    //
+    function executeListenersSyncronously(name, args) { // defaultAction is not used
+      var listeners = _events[name];
+      if (!listeners || listeners.length === 0) return;
+
+      OTHelpers.forEach(listeners, function(listener) { // index
+        (listener.closure || listener.handler).apply(listener.context || null, args);
+      });
+    }
+
+    var executeListeners = syncronous === true ?
+      executeListenersSyncronously : executeListenersAsyncronously;
+
+
+    var removeAllListenersNamed = function (eventName, context) {
+      if (_events[eventName]) {
+        if (context) {
+          // We are removing by context, get only events that don't
+          // match that context
+          _events[eventName] = OTHelpers.filter(_events[eventName], function(listener){
+            return listener.context !== context;
+          });
+        }
+        else {
+          delete _events[eventName];
+        }
+      }
+    };
+
+    var addListeners = OTHelpers.bind(function (eventNames, handler, context, closure) {
+      var listener = {handler: handler};
+      if (context) listener.context = context;
+      if (closure) listener.closure = closure;
+
+      OTHelpers.forEach(eventNames, function(name) {
+        if (!_events[name]) _events[name] = [];
+        _events[name].push(listener);
+      });
+    }, self);
+
+
+    var removeListeners = function (eventNames, handler, context) {
+      function filterHandlerAndContext(listener) {
+        return !(listener.handler === handler && listener.context === context);
+      }
+
+      OTHelpers.forEach(eventNames, OTHelpers.bind(function(name) {
+        if (_events[name]) {
+          _events[name] = OTHelpers.filter(_events[name], filterHandlerAndContext);
+          if (_events[name].length === 0) delete _events[name];
+        }
+      }, self));
+
+    };
+
+    // Execute any listeners bound to the +event+ Event.
+    //
+    // Each handler will be executed async. On completion the defaultAction
+    // handler will be executed with the args.
+    //
+    // @param [Event] event
+    //    An Event object.
+    //
+    // @param [Function, Null, Undefined] defaultAction
+    //    An optional function to execute after every other handler. This will execute even
+    //    if there are listeners bound to this event. +defaultAction+ will be passed
+    //    args as a normal handler would.
+    //
+    // @return this
+    //
+    self.dispatchEvent = function(event, defaultAction) {
+      if (!event.type) {
+        OTHelpers.error('OTHelpers.Eventing.dispatchEvent: Event has no type');
+        OTHelpers.error(event);
+
+        throw new Error('OTHelpers.Eventing.dispatchEvent: Event has no type');
+      }
+
+      if (!event.target) {
+        event.target = this;
+      }
+
+      if (!_events[event.type] || _events[event.type].length === 0) {
+        executeDefaultAction(defaultAction, [event]);
+        return;
+      }
+
+      executeListeners(event.type, [event], defaultAction);
+
+      return this;
+    };
+
+    // Execute each handler for the event called +name+.
+    //
+    // Each handler will be executed async, and any exceptions that they throw will
+    // be caught and logged
+    //
+    // How to pass these?
+    //  * defaultAction
+    //
+    // @example
+    //  foo.on('bar', function(name, message) {
+    //    alert("Hello " + name + ": " + message);
+    //  });
+    //
+    //  foo.trigger('OpenTok', 'asdf');     // -> Hello OpenTok: asdf
+    //
+    //
+    // @param [String] eventName
+    //    The name of this event.
+    //
+    // @param [Array] arguments
+    //    Any additional arguments beyond +eventName+ will be passed to the handlers.
+    //
+    // @return this
+    //
+    self.trigger = function(eventName) {
+      if (!_events[eventName] || _events[eventName].length === 0) {
+        return;
+      }
+
+      var args = Array.prototype.slice.call(arguments);
+
+      // Remove the eventName arg
+      args.shift();
+
+      executeListeners(eventName, args);
+
+      return this;
+    };
+
+   /**
+    * Adds an event handler function for one or more events.
+    *
+    * <p>
+    * The following code adds an event handler for one event:
+    * </p>
+    *
+    * <pre>
+    * obj.on("eventName", function (event) {
+    *     // This is the event handler.
+    * });
+    * </pre>
+    *
+    * <p>If you pass in multiple event names and a handler method, the handler is
+    * registered for each of those events:</p>
+    *
+    * <pre>
+    * obj.on("eventName1 eventName2",
+    *        function (event) {
+    *            // This is the event handler.
+    *        });
+    * </pre>
+    *
+    * <p>You can also pass in a third <code>context</code> parameter (which is optional) to
+    * define the value of <code>this</code> in the handler method:</p>
+    *
+    * <pre>obj.on("eventName",
+    *        function (event) {
+    *            // This is the event handler.
+    *        },
+    *        obj);
+    * </pre>
+    *
+    * <p>
+    * The method also supports an alternate syntax, in which the first parameter is an object
+    * that is a hash map of event names and handler functions and the second parameter (optional)
+    * is the context for this in each handler:
+    * </p>
+    * <pre>
+    * obj.on(
+    *    {
+    *       eventName1: function (event) {
+    *               // This is the handler for eventName1.
+    *           },
+    *       eventName2:  function (event) {
+    *               // This is the handler for eventName2.
+    *           }
+    *    },
+    *    obj);
+    * </pre>
+    *
+    * <p>
+    * If you do not add a handler for an event, the event is ignored locally.
+    * </p>
+    *
+    * @param {String} type The string identifying the type of event. You can specify multiple event
+    * names in this string, separating them with a space. The event handler will process each of
+    * the events.
+    * @param {Function} handler The handler function to process the event. This function takes
+    * the event object as a parameter.
+    * @param {Object} context (Optional) Defines the value of <code>this</code> in the event
+    * handler function.
+    *
+    * @returns {EventDispatcher} The EventDispatcher object.
+    *
+    * @memberOf EventDispatcher
+    * @method #on
+    * @see <a href="#off">off()</a>
+    * @see <a href="#once">once()</a>
+    * @see <a href="#events">Events</a>
+    */
+    self.on = function(eventNames, handlerOrContext, context) {
+      if (typeof(eventNames) === 'string' && handlerOrContext) {
+        addListeners(eventNames.split(' '), handlerOrContext, context);
+      }
+      else {
+        for (var name in eventNames) {
+          if (eventNames.hasOwnProperty(name)) {
+            addListeners([name], eventNames[name], handlerOrContext);
+          }
+        }
+      }
+
+      return this;
+    };
+
+   /**
+    * Removes an event handler or handlers.
+    *
+    * <p>If you pass in one event name and a handler method, the handler is removed for that
+    * event:</p>
+    *
+    * <pre>obj.off("eventName", eventHandler);</pre>
+    *
+    * <p>If you pass in multiple event names and a handler method, the handler is removed for
+    * those events:</p>
+    *
+    * <pre>obj.off("eventName1 eventName2", eventHandler);</pre>
+    *
+    * <p>If you pass in an event name (or names) and <i>no</i> handler method, all handlers are
+    * removed for those events:</p>
+    *
+    * <pre>obj.off("event1Name event2Name");</pre>
+    *
+    * <p>If you pass in no arguments, <i>all</i> event handlers are removed for all events
+    * dispatched by the object:</p>
+    *
+    * <pre>obj.off();</pre>
+    *
+    * <p>
+    * The method also supports an alternate syntax, in which the first parameter is an object that
+    * is a hash map of event names and handler functions and the second parameter (optional) is
+    * the context for this in each handler:
+    * </p>
+    * <pre>
+    * obj.off(
+    *    {
+    *       eventName1: event1Handler,
+    *       eventName2: event2Handler
+    *    });
+    * </pre>
+    *
+    * @param {String} type (Optional) The string identifying the type of event. You can
+    * use a space to specify multiple events, as in "accessAllowed accessDenied
+    * accessDialogClosed". If you pass in no <code>type</code> value (or other arguments),
+    * all event handlers are removed for the object.
+    * @param {Function} handler (Optional) The event handler function to remove. The handler
+    * must be the same function object as was passed into <code>on()</code>. Be careful with
+    * helpers like <code>bind()</code> that return a new function when called. If you pass in
+    * no <code>handler</code>, all event handlers are removed for the specified event
+    * <code>type</code>.
+    * @param {Object} context (Optional) If you specify a <code>context</code>, the event handler
+    * is removed for all specified events and handlers that use the specified context. (The
+    * context must match the context passed into <code>on()</code>.)
+    *
+    * @returns {Object} The object that dispatched the event.
+    *
+    * @memberOf EventDispatcher
+    * @method #off
+    * @see <a href="#on">on()</a>
+    * @see <a href="#once">once()</a>
+    * @see <a href="#events">Events</a>
+    */
+    self.off = function(eventNames, handlerOrContext, context) {
+      if (typeof eventNames === 'string') {
+        if (handlerOrContext && OTHelpers.isFunction(handlerOrContext)) {
+          removeListeners(eventNames.split(' '), handlerOrContext, context);
+        }
+        else {
+          OTHelpers.forEach(eventNames.split(' '), function(name) {
+            removeAllListenersNamed(name, handlerOrContext);
+          }, this);
+        }
+
+      } else if (!eventNames) {
+        // remove all bound events
+        _events = {};
+
+      } else {
+        for (var name in eventNames) {
+          if (eventNames.hasOwnProperty(name)) {
+            removeListeners([name], eventNames[name], handlerOrContext);
+          }
+        }
+      }
+
+      return this;
+    };
+
+
+   /**
+    * Adds an event handler function for one or more events. Once the handler is called,
+    * the specified handler method is removed as a handler for this event. (When you use
+    * the <code>on()</code> method to add an event handler, the handler is <i>not</i>
+    * removed when it is called.) The <code>once()</code> method is the equivilent of
+    * calling the <code>on()</code>
+    * method and calling <code>off()</code> the first time the handler is invoked.
+    *
+    * <p>
+    * The following code adds a one-time event handler for the <code>accessAllowed</code> event:
+    * </p>
+    *
+    * <pre>
+    * obj.once("eventName", function (event) {
+    *    // This is the event handler.
+    * });
+    * </pre>
+    *
+    * <p>If you pass in multiple event names and a handler method, the handler is registered
+    * for each of those events:</p>
+    *
+    * <pre>obj.once("eventName1 eventName2"
+    *          function (event) {
+    *              // This is the event handler.
+    *          });
+    * </pre>
+    *
+    * <p>You can also pass in a third <code>context</code> parameter (which is optional) to define
+    * the value of
+    * <code>this</code> in the handler method:</p>
+    *
+    * <pre>obj.once("eventName",
+    *          function (event) {
+    *              // This is the event handler.
+    *          },
+    *          obj);
+    * </pre>
+    *
+    * <p>
+    * The method also supports an alternate syntax, in which the first parameter is an object that
+    * is a hash map of event names and handler functions and the second parameter (optional) is the
+    * context for this in each handler:
+    * </p>
+    * <pre>
+    * obj.once(
+    *    {
+    *       eventName1: function (event) {
+    *                  // This is the event handler for eventName1.
+    *           },
+    *       eventName2:  function (event) {
+    *                  // This is the event handler for eventName1.
+    *           }
+    *    },
+    *    obj);
+    * </pre>
+    *
+    * @param {String} type The string identifying the type of event. You can specify multiple
+    * event names in this string, separating them with a space. The event handler will process
+    * the first occurence of the events. After the first event, the handler is removed (for
+    * all specified events).
+    * @param {Function} handler The handler function to process the event. This function takes
+    * the event object as a parameter.
+    * @param {Object} context (Optional) Defines the value of <code>this</code> in the event
+    * handler function.
+    *
+    * @returns {Object} The object that dispatched the event.
+    *
+    * @memberOf EventDispatcher
+    * @method #once
+    * @see <a href="#on">on()</a>
+    * @see <a href="#off">off()</a>
+    * @see <a href="#events">Events</a>
+    */
+    self.once = function(eventNames, handler, context) {
+      var names = eventNames.split(' '),
+          fun = OTHelpers.bind(function() {
+            var result = handler.apply(context || null, arguments);
+            removeListeners(names, handler, context);
+
+            return result;
+          }, this);
+
+      addListeners(names, handler, context, fun);
+      return this;
+    };
+
+
+    /**
+    * Deprecated; use <a href="#on">on()</a> or <a href="#once">once()</a> instead.
+    * <p>
+    * This method registers a method as an event listener for a specific event.
+    * <p>
+    *
+    * <p>
+    *   If a handler is not registered for an event, the event is ignored locally. If the
+    *   event listener function does not exist, the event is ignored locally.
+    * </p>
+    * <p>
+    *   Throws an exception if the <code>listener</code> name is invalid.
+    * </p>
+    *
+    * @param {String} type The string identifying the type of event.
+    *
+    * @param {Function} listener The function to be invoked when the object dispatches the event.
+    *
+    * @param {Object} context (Optional) Defines the value of <code>this</code> in the event
+    * handler function.
+    *
+    * @memberOf EventDispatcher
+    * @method #addEventListener
+    * @see <a href="#on">on()</a>
+    * @see <a href="#once">once()</a>
+    * @see <a href="#events">Events</a>
+    */
+    // See 'on' for usage.
+    // @depreciated will become a private helper function in the future.
+    self.addEventListener = function(eventName, handler, context) {
+      OTHelpers.warn('The addEventListener() method is deprecated. Use on() or once() instead.');
+      addListeners([eventName], handler, context);
+    };
+
+
+    /**
+    * Deprecated; use <a href="#on">on()</a> or <a href="#once">once()</a> instead.
+    * <p>
+    * Removes an event listener for a specific event.
+    * <p>
+    *
+    * <p>
+    *   Throws an exception if the <code>listener</code> name is invalid.
+    * </p>
+    *
+    * @param {String} type The string identifying the type of event.
+    *
+    * @param {Function} listener The event listener function to remove.
+    *
+    * @param {Object} context (Optional) If you specify a <code>context</code>, the event
+    * handler is removed for all specified events and event listeners that use the specified
+    context. (The context must match the context passed into
+    * <code>addEventListener()</code>.)
+    *
+    * @memberOf EventDispatcher
+    * @method #removeEventListener
+    * @see <a href="#off">off()</a>
+    * @see <a href="#events">Events</a>
+    */
+    // See 'off' for usage.
+    // @depreciated will become a private helper function in the future.
+    self.removeEventListener = function(eventName, handler, context) {
+      OTHelpers.warn('The removeEventListener() method is deprecated. Use off() instead.');
+      removeListeners([eventName], handler, context);
+    };
+
+
+
+
+
+    return self;
+  };
+
+  OTHelpers.eventing.Event = function() {
+
+    return function (type, cancelable) {
+      this.type = type;
+      this.cancelable = cancelable !== undefined ? cancelable : true;
+
+      var _defaultPrevented = false;
+
+      this.preventDefault = function() {
+        if (this.cancelable) {
+          _defaultPrevented = true;
+        } else {
+          OTHelpers.warn('Event.preventDefault :: Trying to preventDefault ' +
+            'on an Event that isn\'t cancelable');
+        }
+      };
+
+      this.isDefaultPrevented = function() {
+        return _defaultPrevented;
+      };
+    };
+
+  };
+  
+})(window, window.OTHelpers);
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+// tb_require('./callbacks.js')
+
+// DOM helpers
+(function(window, OTHelpers, undefined) {
+
+OTHelpers.isElementNode = function(node) {
+    return node && typeof node === 'object' && node.nodeType == 1;
+};
+
+// Returns true if the client supports element.classList
+OTHelpers.supportsClassList = function() {
+    var hasSupport = typeof(document !== "undefined") && ("classList" in document.createElement("a"));
+    OTHelpers.supportsClassList = function() { return hasSupport; };
+
+    return hasSupport;
+};
+
+OTHelpers.removeElement = function(element) {
+    if (element && element.parentNode) {
+        element.parentNode.removeChild(element);
+    }
+};
+
+OTHelpers.removeElementById = function(elementId) {
+    this.removeElement(OTHelpers(elementId));
+};
+
+OTHelpers.removeElementsByType = function(parentElem, type) {
+    if (!parentElem) return;
+
+    var elements = parentElem.getElementsByTagName(type);
+
+    // elements is a "live" NodesList collection. Meaning that the collection
+    // itself will be mutated as we remove elements from the DOM. This means
+    // that "while there are still elements" is safer than "iterate over each
+    // element" as the collection length and the elements indices will be modified
+    // with each iteration.
+    while (elements.length) {
+        parentElem.removeChild(elements[0]);
+    }
+};
+
+OTHelpers.emptyElement = function(element) {
+    while (element.firstChild) {
+        element.removeChild(element.firstChild);
+    }
+    return element;
+};
+
+OTHelpers.createElement = function(nodeName, attributes, children, doc) {
+    var element = (doc || document).createElement(nodeName);
+
+    if (attributes) {
+        for (var name in attributes) {
+            if (typeof(attributes[name]) === 'object') {
+                if (!element[name]) element[name] = {};
+
+                var subAttrs = attributes[name];
+                for (var n in subAttrs) {
+                    element[name][n] = subAttrs[n];
+                }
+            }
+            else if (name === 'className') {
+                element.className = attributes[name];
+            }
+            else {
+                element.setAttribute(name, attributes[name]);
+            }
+        }
+    }
+
+    var setChildren = function(child) {
+        if(typeof child === 'string') {
+            element.innerHTML = element.innerHTML + child;
+        } else {
+            element.appendChild(child);
+        }
+    };
+
+    if(OTHelpers.isArray(children)) {
+        OTHelpers.forEach(children, setChildren);
+    } else if(children) {
+        setChildren(children);
+    }
+
+    return element;
+};
+
+OTHelpers.createButton = function(innerHTML, attributes, events) {
+    var button = OTHelpers.createElement('button', attributes, innerHTML);
+
+    if (events) {
+        for (var name in events) {
+            if (events.hasOwnProperty(name)) {
+                OTHelpers.on(button, name, events[name]);
+            }
+        }
+
+        button._boundEvents = events;
+    }
+
+    return button;
+};
+
+// Helper function for adding event listeners to dom elements.
+// WARNING: This doesn't preserve event types, your handler could be getting all kinds of different
+// parameters depending on the browser. You also may have different scopes depending on the browser
+// and bubbling and cancelable are not supported.
+OTHelpers.on = function(element, eventName,  handler) {
+    if (element.addEventListener) {
+        element.addEventListener(eventName, handler, false);
+    } else if (element.attachEvent) {
+        element.attachEvent("on" + eventName, handler);
+    } else {
+        var oldHandler = element["on"+eventName];
+        element["on"+eventName] = function() {
+          handler.apply(this, arguments);
+          if (oldHandler) oldHandler.apply(this, arguments);
+        };
+    }
+    return element;
+};
+
+// Helper function for removing event listeners from dom elements.
+OTHelpers.off = function(element, eventName, handler) {
+    if (element.removeEventListener) {
+        element.removeEventListener (eventName, handler,false);
+    }
+    else if (element.detachEvent) {
+        element.detachEvent("on" + eventName, handler);
+    }
+};
+
+
+// Detects when an element is not part of the document flow because it or one of it's ancesters has display:none.
+OTHelpers.isDisplayNone = function(element) {
+    if ( (element.offsetWidth === 0 || element.offsetHeight === 0) && OTHelpers.css(element, 'display') === 'none') return true;
+    if (element.parentNode && element.parentNode.style) return OTHelpers.isDisplayNone(element.parentNode);
+    return false;
+};
+
+OTHelpers.findElementWithDisplayNone = function(element) {
+    if ( (element.offsetWidth === 0 || element.offsetHeight === 0) && OTHelpers.css(element, 'display') === 'none') return element;
+    if (element.parentNode && element.parentNode.style) return OTHelpers.findElementWithDisplayNone(element.parentNode);
+    return null;
+};
+
+function objectHasProperties(obj) {
+    for (var key in obj) {
+        if (obj.hasOwnProperty(key)) return true;
+    }
+    return false;
+}
+
+
+// Allows an +onChange+ callback to be triggered when specific style properties
+// of +element+ are notified. The callback accepts a single parameter, which is
+// a hash where the keys are the style property that changed and the values are
+// an array containing the old and new values ([oldValue, newValue]).
+//
+// Width and Height changes while the element is display: none will not be
+// fired until such time as the element becomes visible again.
+//
+// This function returns the MutationObserver itself. Once you no longer wish
+// to observe the element you should call disconnect on the observer.
+//
+// Observing changes:
+//  // observe changings to the width and height of object
+//  dimensionsObserver = OTHelpers.observeStyleChanges(object, ['width', 'height'], function(changeSet) {
+//      OT.debug("The new width and height are " + changeSet.width[1] + ',' + changeSet.height[1]);
+//  });
+//
+// Cleaning up
+//  // stop observing changes
+//  dimensionsObserver.disconnect();
+//  dimensionsObserver = null;
+//
+OTHelpers.observeStyleChanges = function(element, stylesToObserve, onChange) {
+    var oldStyles = {};
+
+    var getStyle = function getStyle(style) {
+            switch (style) {
+            case 'width':
+                return OTHelpers.width(element);
+
+            case 'height':
+                return OTHelpers.height(element);
+
+            default:
+                return OTHelpers.css(element);
+            }
+        };
+
+    // get the inital values
+    OTHelpers.forEach(stylesToObserve, function(style) {
+        oldStyles[style] = getStyle(style);
+    });
+
+    var observer = new MutationObserver(function(mutations) {
+        var changeSet = {};
+
+        OTHelpers.forEach(mutations, function(mutation) {
+            if (mutation.attributeName !== 'style') return;
+
+            var isHidden = OTHelpers.isDisplayNone(element);
+
+            OTHelpers.forEach(stylesToObserve, function(style) {
+                if(isHidden && (style == 'width' || style == 'height')) return;
+                
+                var newValue = getStyle(style);
+
+                if (newValue !== oldStyles[style]) {
+                    // OT.debug("CHANGED " + style + ": " + oldStyles[style] + " -> " + newValue);
+
+                    changeSet[style] = [oldStyles[style], newValue];
+                    oldStyles[style] = newValue;
+                }
+            });
+        });
+
+        if (objectHasProperties(changeSet)) {
+            // Do this after so as to help avoid infinite loops of mutations.
+            OTHelpers.callAsync(function() {
+                onChange.call(null, changeSet);
+            });
+        }
+    });
+
+    observer.observe(element, {
+        attributes:true,
+        attributeFilter: ['style'],
+        childList:false,
+        characterData:false,
+        subtree:false
+    });
+
+    return observer;
+};
+
+
+// trigger the +onChange+ callback whenever
+// 1. +element+ is removed
+// 2. or an immediate child of +element+ is removed.
+//
+// This function returns the MutationObserver itself. Once you no longer wish
+// to observe the element you should call disconnect on the observer.
+//
+// Observing changes:
+//  // observe changings to the width and height of object
+//  nodeObserver = OTHelpers.observeNodeOrChildNodeRemoval(object, function(removedNodes) {
+//      OT.debug("Some child nodes were removed");
+//      OTHelpers.forEach(removedNodes, function(node) {
+//          OT.debug(node);
+//      });
+//  });
+//
+// Cleaning up
+//  // stop observing changes
+//  nodeObserver.disconnect();
+//  nodeObserver = null;
+//
+OTHelpers.observeNodeOrChildNodeRemoval = function(element, onChange) {
+    var observer = new MutationObserver(function(mutations) {
+        var removedNodes = [];
+
+        OTHelpers.forEach(mutations, function(mutation) {
+            if (mutation.removedNodes.length) {
+                removedNodes = removedNodes.concat(Array.prototype.slice.call(mutation.removedNodes));
+            }
+        });
+
+        if (removedNodes.length) {
+            // Do this after so as to help avoid infinite loops of mutations.
+            OTHelpers.callAsync(function() {
+                onChange(removedNodes);
+            });
+        }
+    });
+
+    observer.observe(element, {
+        attributes:false,
+        childList:true,
+        characterData:false,
+        subtree:true
+    });
+
+    return observer;
+};
+
+})(window, window.OTHelpers);
+
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+// tb_require('./dom.js')
+
+(function(window, OTHelpers, undefined) {
+
+  OTHelpers.Modal = function(options) {
+
+    OTHelpers.eventing(this, true);
+
+    var callback = arguments[arguments.length - 1];
+
+    if(!OTHelpers.isFunction(callback)) {
+      throw new Error('OTHelpers.Modal2 must be given a callback');
+    }
+
+    if(arguments.length < 2) {
+      options = {};
+    }
+
+    var domElement = document.createElement('iframe');
+
+    domElement.id = options.id || OTHelpers.uuid();
+    domElement.style.position = 'absolute';
+    domElement.style.position = 'fixed';
+    domElement.style.height = '100%';
+    domElement.style.width = '100%';
+    domElement.style.top = '0px';
+    domElement.style.left = '0px';
+    domElement.style.right = '0px';
+    domElement.style.bottom = '0px';
+    domElement.style.zIndex = 1000;
+    domElement.style.border = '0';
+
+    try {
+      domElement.style.backgroundColor = 'rgba(0,0,0,0.2)';
+    } catch (err) {
+      // Old IE browsers don't support rgba and we still want to show the upgrade message
+      // but we just make the background of the iframe completely transparent.
+      domElement.style.backgroundColor = 'transparent';
+      domElement.setAttribute('allowTransparency', 'true');
+    }
+
+    domElement.scrolling = 'no';
+    domElement.setAttribute('scrolling', 'no');
+
+    var wrappedCallback = function() {
+      var doc = domElement.contentDocument || domElement.contentWindow.document;
+      doc.body.style.backgroundColor = 'transparent';
+      doc.body.style.border = 'none';
+      callback(
+        domElement.contentWindow,
+        doc
+      );
+    };
+
+    document.body.appendChild(domElement);
+    
+    if(OTHelpers.browserVersion().iframeNeedsLoad) {
+      OTHelpers.on(domElement, 'load', wrappedCallback);
+    } else {
+      setTimeout(wrappedCallback);
+    }
+
+    this.close = function() {
+      OTHelpers.removeElement(domElement);
+      this.trigger('closed');
+      this.element = domElement = null;
+      return this;
+    };
+
+    this.element = domElement;
+
+  };
+  
+})(window, window.OTHelpers);
+
+/*
+ * getComputedStyle from 
+ * https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js
+
+// tb_require('../helpers.js')
+// tb_require('./dom.js')
+
+/*jshint strict: false, eqnull: true, browser:true, smarttabs:true*/
+
+(function(window, OTHelpers, undefined) {
+
+  /*jshint eqnull: true, browser: true */
+
+
+  function getPixelSize(element, style, property, fontSize) {
+    var sizeWithSuffix = style[property],
+        size = parseFloat(sizeWithSuffix),
+        suffix = sizeWithSuffix.split(/\d/)[0],
+        rootSize;
+
+    fontSize = fontSize != null ?
+      fontSize : /%|em/.test(suffix) && element.parentElement ?
+        getPixelSize(element.parentElement, element.parentElement.currentStyle, 'fontSize', null) :
+        16;
+    rootSize = property === 'fontSize' ?
+      fontSize : /width/i.test(property) ? element.clientWidth : element.clientHeight;
+
+    return (suffix === 'em') ?
+      size * fontSize : (suffix === 'in') ?
+        size * 96 : (suffix === 'pt') ?
+          size * 96 / 72 : (suffix === '%') ?
+            size / 100 * rootSize : size;
+  }
+
+  function setShortStyleProperty(style, property) {
+    var
+    borderSuffix = property === 'border' ? 'Width' : '',
+    t = property + 'Top' + borderSuffix,
+    r = property + 'Right' + borderSuffix,
+    b = property + 'Bottom' + borderSuffix,
+    l = property + 'Left' + borderSuffix;
+
+    style[property] = (style[t] === style[r] === style[b] === style[l] ? [style[t]]
+    : style[t] === style[b] && style[l] === style[r] ? [style[t], style[r]]
+    : style[l] === style[r] ? [style[t], style[r], style[b]]
+    : [style[t], style[r], style[b], style[l]]).join(' ');
+  }
+
+  function CSSStyleDeclaration(element) {
+    var currentStyle = element.currentStyle,
+        style = this,
+        fontSize = getPixelSize(element, currentStyle, 'fontSize', null),
+        property;
+
+    for (property in currentStyle) {
+      if (/width|height|margin.|padding.|border.+W/.test(property) && style[property] !== 'auto') {
+        style[property] = getPixelSize(element, currentStyle, property, fontSize) + 'px';
+      } else if (property === 'styleFloat') {
+        /*jshint -W069 */
+        style['float'] = currentStyle[property];
+      } else {
+        style[property] = currentStyle[property];
+      }
+    }
+
+    setShortStyleProperty(style, 'margin');
+    setShortStyleProperty(style, 'padding');
+    setShortStyleProperty(style, 'border');
+
+    style.fontSize = fontSize + 'px';
+
+    return style;
+  }
+
+  CSSStyleDeclaration.prototype = {
+    constructor: CSSStyleDeclaration,
+    getPropertyPriority: function () {},
+    getPropertyValue: function ( prop ) {
+      return this[prop] || '';
+    },
+    item: function () {},
+    removeProperty: function () {},
+    setProperty: function () {},
+    getPropertyCSSValue: function () {}
+  };
+
+  function getComputedStyle(element) {
+    return new CSSStyleDeclaration(element);
+  }
+
+
+  OTHelpers.getComputedStyle = function(element) {
+    if(element &&
+        element.ownerDocument &&
+        element.ownerDocument.defaultView &&
+        element.ownerDocument.defaultView.getComputedStyle) {
+      return element.ownerDocument.defaultView.getComputedStyle(element);
+    } else {
+      return getComputedStyle(element);
+    }
+  };
+
+})(window, window.OTHelpers);
+
+// DOM Attribute helpers helpers
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+// tb_require('./dom.js')
+
+(function(window, OTHelpers, undefined) {
+
+OTHelpers.addClass = function(element, value) {
+    // Only bother targeting Element nodes, ignore Text Nodes, CDATA, etc
+    if (element.nodeType !== 1) {
+        return;
+    }
+
+    var classNames = OTHelpers.trim(value).split(/\s+/),
+        i, l;
+
+    if (OTHelpers.supportsClassList()) {
+        for (i=0, l=classNames.length; i<l; ++i) {
+            element.classList.add(classNames[i]);
+        }
+
+        return;
+    }
+
+    // Here's our fallback to browsers that don't support element.classList
+
+    if (!element.className && classNames.length === 1) {
+        element.className = value;
+    }
+    else {
+        var setClass = " " + element.className + " ";
+
+        for (i=0, l=classNames.length; i<l; ++i) {
+            if ( !~setClass.indexOf( " " + classNames[i] + " ")) {
+                setClass += classNames[i] + " ";
+            }
+        }
+
+        element.className = OTHelpers.trim(setClass);
+    }
+
+    return this;
+};
+
+OTHelpers.removeClass = function(element, value) {
+    if (!value) return;
+
+    // Only bother targeting Element nodes, ignore Text Nodes, CDATA, etc
+    if (element.nodeType !== 1) {
+        return;
+    }
+
+    var newClasses = OTHelpers.trim(value).split(/\s+/),
+        i, l;
+
+    if (OTHelpers.supportsClassList()) {
+        for (i=0, l=newClasses.length; i<l; ++i) {
+            element.classList.remove(newClasses[i]);
+        }
+
+        return;
+    }
+
+    var className = (" " + element.className + " ").replace(/[\s+]/, ' ');
+
+    for (i=0,l=newClasses.length; i<l; ++i) {
+        className = className.replace(' ' + newClasses[i] + ' ', ' ');
+    }
+
+    element.className = OTHelpers.trim(className);
+
+    return this;
+};
+
+
+/**
+ * Methods to calculate element widths and heights.
+ */
+
+var _width = function(element) {
+        if (element.offsetWidth > 0) {
+            return element.offsetWidth + 'px';
+        }
+
+        return OTHelpers.css(element, 'width');
+    },
+
+    _height = function(element) {
+        if (element.offsetHeight > 0) {
+            return element.offsetHeight + 'px';
+        }
+
+        return OTHelpers.css(element, 'height');
+    };
+
+OTHelpers.width = function(element, newWidth) {
+    if (newWidth) {
+        OTHelpers.css(element, 'width', newWidth);
+        return this;
+    }
+    else {
+        if (OTHelpers.isDisplayNone(element)) {
+            // We can't get the width, probably since the element is hidden.
+            return OTHelpers.makeVisibleAndYield(element, function() {
+                return _width(element);
+            });
+        }
+        else {
+            return _width(element);
+        }
+    }
+};
+
+OTHelpers.height = function(element, newHeight) {
+    if (newHeight) {
+        OTHelpers.css(element, 'height', newHeight);
+        return this;
+    }
+    else {
+        if (OTHelpers.isDisplayNone(element)) {
+            // We can't get the height, probably since the element is hidden.
+            return OTHelpers.makeVisibleAndYield(element, function() {
+                return _height(element);
+            });
+        }
+        else {
+            return _height(element);
+        }
+    }
+};
+
+// Centers +element+ within the window. You can pass through the width and height
+// if you know it, if you don't they will be calculated for you.
+OTHelpers.centerElement = function(element, width, height) {
+    if (!width) width = parseInt(OTHelpers.width(element), 10);
+    if (!height) height = parseInt(OTHelpers.height(element), 10);
+
+    var marginLeft = -0.5 * width + "px";
+    var marginTop = -0.5 * height + "px";
+    OTHelpers.css(element, "margin", marginTop + " 0 0 " + marginLeft);
+    OTHelpers.addClass(element, "OT_centered");
+};
+
+})(window, window.OTHelpers);
+
+// CSS helpers helpers
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+// tb_require('./dom.js')
+// tb_require('./getcomputedstyle.js')
+
+(function(window, OTHelpers, undefined) {
+
+  var displayStateCache = {},
+      defaultDisplays = {};
+
+  var defaultDisplayValueForElement = function(element) {
+      if (defaultDisplays[element.ownerDocument] &&
+        defaultDisplays[element.ownerDocument][element.nodeName]) {
+        return defaultDisplays[element.ownerDocument][element.nodeName];
+      }
+
+      if (!defaultDisplays[element.ownerDocument]) defaultDisplays[element.ownerDocument] = {};
+    
+      // We need to know what display value to use for this node. The easiest way
+      // is to actually create a node and read it out.
+      var testNode = element.ownerDocument.createElement(element.nodeName),
+          defaultDisplay;
+
+      element.ownerDocument.body.appendChild(testNode);
+      defaultDisplay = defaultDisplays[element.ownerDocument][element.nodeName] =
+        OTHelpers.css(testNode, 'display');
+
+      OTHelpers.removeElement(testNode);
+      testNode = null;
+
+      return defaultDisplay;
+    };
+
+  var isHidden = function(element) {
+    var computedStyle = OTHelpers.getComputedStyle(element);
+    return computedStyle.getPropertyValue('display') === 'none';
+  };
+
+  OTHelpers.show = function(element) {
+    var display = element.style.display;
+
+    if (display === '' || display === 'none') {
+      element.style.display = displayStateCache[element] || '';
+      delete displayStateCache[element];
+    }
+
+    if (isHidden(element)) {
+      // It's still hidden so there's probably a stylesheet that declares this
+      // element as display:none;
+      displayStateCache[element] = 'none';
+
+      element.style.display = defaultDisplayValueForElement(element);
+    }
+
+    return this;
+  };
+
+  OTHelpers.hide = function(element) {
+    if (element.style.display === 'none') return;
+
+    displayStateCache[element] = element.style.display;
+    element.style.display = 'none';
+
+    return this;
+  };
+
+  OTHelpers.css = function(element, nameOrHash, value) {
+    if (typeof(nameOrHash) !== 'string') {
+      var style = element.style;
+
+      for (var cssName in nameOrHash) {
+        style[cssName] = nameOrHash[cssName];
+      }
+
+      return this;
+
+    } else if (value !== undefined) {
+      element.style[nameOrHash] = value;
+      return this;
+
+    } else {
+      // Normalise vendor prefixes from the form MozTranform to -moz-transform
+      // except for ms extensions, which are weird...
+
+      var name = nameOrHash.replace( /([A-Z]|^ms)/g, '-$1' ).toLowerCase(),
+          computedStyle = OTHelpers.getComputedStyle(element),
+          currentValue = computedStyle.getPropertyValue(name);
+
+      if (currentValue === '') {
+        currentValue = element.style[name];
+      }
+
+      return currentValue;
+    }
+  };
+
+
+// Apply +styles+ to +element+ while executing +callback+, restoring the previous
+// styles after the callback executes.
+  OTHelpers.applyCSS = function(element, styles, callback) {
+    var oldStyles = {},
+        name,
+        ret;
+
+    // Backup the old styles
+    for (name in styles) {
+      if (styles.hasOwnProperty(name)) {
+        // We intentionally read out of style here, instead of using the css
+        // helper. This is because the css helper uses querySelector and we
+        // only want to pull values out of the style (domeElement.style) hash.
+        oldStyles[name] = element.style[name];
+
+        OTHelpers.css(element, name, styles[name]);
+      }
+    }
+
+    ret = callback();
+
+    // Restore the old styles
+    for (name in styles) {
+      if (styles.hasOwnProperty(name)) {
+        OTHelpers.css(element, name, oldStyles[name] || '');
+      }
+    }
+
+    return ret;
+  };
+
+// Make +element+ visible while executing +callback+.
+  OTHelpers.makeVisibleAndYield = function(element, callback) {
+    // find whether it's the element or an ancester that's display none and
+    // then apply to whichever it is
+    var targetElement = OTHelpers.findElementWithDisplayNone(element);
+    if (!targetElement) return;
+
+    return OTHelpers.applyCSS(targetElement, {
+      display: 'block',
+      visibility: 'hidden'
+    }, callback);
+  };
+
+})(window, window.OTHelpers);
+
+// AJAX helpers
+
+/*jshint browser:true, smarttabs:true*/
+
+// tb_require('../helpers.js')
+
+(function(window, OTHelpers, undefined) {
+
+  function formatPostData(data) { //, contentType
+    // If it's a string, we assume it's properly encoded
+    if (typeof(data) === 'string') return data;
+
+    var queryString = [];
+
+    for (var key in data) {
+      queryString.push(
+        encodeURIComponent(key) + '=' + encodeURIComponent(data[key])
+      );
+    }
+
+    return queryString.join('&').replace(/\+/g, '%20');
+  }
+
+  OTHelpers.getJSON = function(url, options, callback) {
+    options = options || {};
+
+    var done = function(error, event) {
+      if(error) {
+        callback(error, event && event.target && event.target.responseText);
+      } else {
+        var response;
+
+        try {
+          response = JSON.parse(event.target.responseText);
+        } catch(e) {
+          // Badly formed JSON
+          callback(e, event && event.target && event.target.responseText);
+          return;
+        }
+
+        callback(null, response, event);
+      }
+    };
+
+    if(options.xdomainrequest) {
+      OTHelpers.xdomainRequest(url, { method: 'GET' }, done);
+    } else {
+      var extendedHeaders = OTHelpers.extend({
+        'Accept': 'application/json'
+      }, options.headers || {});
+
+      OTHelpers.get(url, OTHelpers.extend(options || {}, {
+        headers: extendedHeaders
+      }), done);
+    }
+
+  };
+
+  OTHelpers.xdomainRequest = function(url, options, callback) {
+    /*global XDomainRequest*/
+    var xdr = new XDomainRequest(),
+        _options = options || {},
+        _method = _options.method;
+
+    if(!_method) {
+      callback(new Error('No HTTP method specified in options'));
+      return;
+    }
+
+    _method = _method.toUpperCase();
+
+    if(!(_method === 'GET' || _method === 'POST')) {
+      callback(new Error('HTTP method can only be '));
+      return;
+    }
+
+    function done(err, event) {
+      xdr.onload = xdr.onerror = xdr.ontimeout = function() {};
+      xdr = void 0;
+      callback(err, event);
+    }
+
+
+    xdr.onload = function() {
+      done(null, {
+        target: {
+          responseText: xdr.responseText,
+          headers: {
+            'content-type': xdr.contentType
+          }
+        }
+      });
+    };
+
+    xdr.onerror = function() {
+      done(new Error('XDomainRequest of ' + url + ' failed'));
+    };
+
+    xdr.ontimeout = function() {
+      done(new Error('XDomainRequest of ' + url + ' timed out'));
+    };
+
+    xdr.open(_method, url);
+    xdr.send(options.body && formatPostData(options.body));
+
+  };
+
+  OTHelpers.request = function(url, options, callback) {
+    var request = new XMLHttpRequest(),
+        _options = options || {},
+        _method = _options.method;
+
+    if(!_method) {
+      callback(new Error('No HTTP method specified in options'));
+      return;
+    }
+
+    // Setup callbacks to correctly respond to success and error callbacks. This includes
+    // interpreting the responses HTTP status, which XmlHttpRequest seems to ignore
+    // by default.
+    if(callback) {
+      request.addEventListener('load', function(event) {
+        var status = event.target.status;
+
+        // We need to detect things that XMLHttpRequest considers a success,
+        // but we consider to be failures.
+        if ( status >= 200 && status < 300 || status === 304 ) {
+          callback(null, event);
+        } else {
+          callback(event);
+        }
+      }, false);
+
+      request.addEventListener('error', callback, false);
+    }
+
+    request.open(options.method, url, true);
+
+    if (!_options.headers) _options.headers = {};
+
+    for (var name in _options.headers) {
+      request.setRequestHeader(name, _options.headers[name]);
+    }
+
+    request.send(options.body && formatPostData(options.body));
+  };
+
+  OTHelpers.get = function(url, options, callback) {
+    var _options = OTHelpers.extend(options || {}, {
+      method: 'GET'
+    });
+    OTHelpers.request(url, _options, callback);
+  };
+
+  OTHelpers.post = function(url, options, callback) {
+    var _options = OTHelpers.extend(options || {}, {
+      method: 'POST'
+    });
+
+    if(_options.xdomainrequest) {
+      OTHelpers.xdomainRequest(url, _options, callback);
+    } else {
+      OTHelpers.request(url, _options, callback);
+    }
+  };
+
+})(window, window.OTHelpers);
+!(function() {
+
+  OT.Dialogs = {};
+
+  var addCss = function(document, url, callback) {
+    var head = document.head || document.getElementsByTagName('head')[0];
+    var cssTag = OT.$.createElement('link', {
+      type: 'text/css',
+      media: 'screen',
+      rel: 'stylesheet',
+      href: url
+    });
+    head.appendChild(cssTag);
+    OT.$.on(cssTag, 'error', function(error) {
+      OT.error('Could not load CSS for dialog', url, error && error.message || error);
+    });
+    OT.$.on(cssTag, 'load', callback);
+  };
+
+  var addDialogCSS = function(document, urls, callback) {
+    var allURLs = [
+      '//fonts.googleapis.com/css?family=Didact+Gothic',
+      OT.properties.cssURL
+    ].concat(urls);
+    var remainingStylesheets = allURLs.length;
+    OT.$.forEach(allURLs, function(stylesheetUrl) {
+      addCss(document, stylesheetUrl, function() {
+        if(--remainingStylesheets <= 0) {
+          callback();
+        }
+      });
+    });
+
+  };
+  
+  var templateElement = function(classes, children, tagName) {
+    var el = OT.$.createElement(tagName || 'div', { 'class': classes }, children, this);
+    el.on = OT.$.bind(OT.$.on, OT.$, el);
+    return el;
+  };
+
+  OT.Dialogs.AllowDeny = {};
+  OT.Dialogs.AllowDeny.Chrome = {};
+  OT.Dialogs.AllowDeny.Firefox = {};
+
+  OT.Dialogs.AllowDeny.Chrome.initialPrompt = function() {
+    var modal = new OT.$.Modal(function(window, document) {
+
+      var el = templateElement.bind(document),
+          close, root;
+
+      close = el('OT_closeButton', '&times;')
+        .on('click', function() {
+          modal.close();
+        });
+
+      root = el('OT_root OT_dialog OT_dialog-allow-deny-chrome-first', [
+        close,
+        el('OT_dialog-messages', [
+          el('OT_dialog-messages-main', 'Allow camera and mic access'),
+          el('OT_dialog-messages-minor', 'Click the Allow button in the upper-right corner ' +
+            'of your browser to enable real-time communication.'),
+          el('OT_dialog-allow-highlight-chrome')
+        ])
+      ]);
+
+      addDialogCSS(document, [], function() {
+        document.body.appendChild(root);
+      });
+
+    });
+    return modal;
+  };
+
+  OT.Dialogs.AllowDeny.Chrome.previouslyDenied = function(website) {
+    var modal = new OT.$.Modal(function(window, document) {
+
+      var el = templateElement.bind(document),
+          close,
+          root;
+
+      close = el('OT_closeButton', '&times;')
+        .on('click', function() {
+          modal.close();
+        });
+
+      root = el('OT_root OT_dialog OT_dialog-allow-deny-chrome-pre-denied', [
+        close,
+        el('OT_dialog-messages', [
+          el('OT_dialog-messages-main', 'Allow camera and mic access'),
+          el('OT_dialog-messages-minor', [
+            'To interact with this app, follow these 3 steps:',
+            el('OT_dialog-3steps', [
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '1'),
+                'Find this icon in the URL bar and click it',
+                el('OT_dialog-allow-camera-icon')
+              ]),
+              el('OT_dialog-3steps-seperator'),
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '2'),
+                'Select "Ask if ' + website + ' wants to access your camera and mic" ' +
+                  'and then click Done.'
+              ]),
+              el('OT_dialog-3steps-seperator'),
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '3'),
+                'Refresh your browser.'
+              ])
+            ])
+          ])
+        ])
+      ]);
+
+      addDialogCSS(document, [], function() {
+        document.body.appendChild(root);
+      });
+
+    });
+    return modal;
+  };
+
+  OT.Dialogs.AllowDeny.Chrome.deniedNow = function() {
+    var modal = new OT.$.Modal(function(window, document) {
+
+      var el = templateElement.bind(document),
+          root;
+
+      root = el('OT_root OT_dialog-blackout',
+        el('OT_dialog OT_dialog-allow-deny-chrome-now-denied', [
+          el('OT_dialog-messages', [
+            el('OT_dialog-messages-main ',
+              el('OT_dialog-allow-camera-icon')
+            ),
+            el('OT_dialog-messages-minor',
+              'Find & click this icon to allow camera and mic access.'
+            )
+          ])
+        ])
+      );
+
+      addDialogCSS(document, [], function() {
+        document.body.appendChild(root);
+      });
+
+    });
+    return modal;
+  };
+
+  OT.Dialogs.AllowDeny.Firefox.maybeDenied = function() {
+    var modal = new OT.$.Modal(function(window, document) {
+
+      var el = templateElement.bind(document),
+          close,
+          root;
+
+      close = el('OT_closeButton', '&times;')
+        .on('click', function() {
+          modal.close();
+        });
+
+      root = el('OT_root OT_dialog OT_dialog-allow-deny-firefox-maybe-denied', [
+        close,
+        el('OT_dialog-messages', [
+          el('OT_dialog-messages-main', 'Please allow camera & mic access'),
+          el('OT_dialog-messages-minor', [
+            'To interact with this app, follow these 3 steps:',
+            el('OT_dialog-3steps', [
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '1'),
+                'Reload the page, or click the camera icon ' +
+                  'in the browser URL bar.'
+              ]),
+              el('OT_dialog-3steps-seperator'),
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '2'),
+                'In the menu, select your camera & mic.'
+              ]),
+              el('OT_dialog-3steps-seperator'),
+              el('OT_dialog-3steps-step', [
+                el('OT_dialog-3steps-step-num', '3'),
+                'Click "Share Selected Devices."'
+              ])
+            ])
+          ])
+        ])
+      ]);
+
+      addDialogCSS(document, [], function() {
+        document.body.appendChild(root);
+      });
+
+    });
+    return modal;
+  };
+
+
+  OT.Dialogs.AllowDeny.Firefox.denied = function() {
+    var modal = new OT.$.Modal(function(window, document) {
+
+      var el = templateElement.bind(document),
+          btn = templateElement.bind(document, 'OT_dialog-button OT_dialog-button-large'),
+          root,
+          refreshButton;
+
+      refreshButton = btn('Reload')
+        .on('click', function() {
+          modal.trigger('refresh');
+        });
+
+      root = el('OT_root OT_dialog-blackout',
+        el('OT_dialog OT_dialog-allow-deny-firefox-denied', [
+          el('OT_dialog-messages', [
+            el('OT_dialog-messages-minor',
+              'Access to camera and microphone has been denied. ' +
+              'Click the button to reload page.'
+            )
+          ]),
+          el('OT_dialog-single-button', refreshButton)
+        ])
+      );
+
+      addDialogCSS(document, [], function() {
+        document.body.appendChild(root);
+      });
+
+    });
+    return modal;
+  };
+
+})();
+!(function(window) {
+
+  /* global OTHelpers */
+
+  if (!window.OT) window.OT = {};
+
+  // Bring OTHelpers in as OT.$
+  OT.$ = OTHelpers.noConflict();
+
+  // Allow events to be bound on OT
+  OT.$.eventing(OT);
+
+  // REMOVE THIS POST IE MERGE
+
+  OT.$.defineGetters = function(self, getters, enumerable) {
+    var propsDefinition = {};
+
+    if (enumerable === void 0) enumerable = false;
+
+    for (var key in getters) {
+      propsDefinition[key] = {
+        get: getters[key],
+        enumerable: enumerable
+      };
+    }
+
+    Object.defineProperties(self, propsDefinition);
+  };
+
+  // STOP REMOVING HERE
+
+  // OT.$.Modal was OT.Modal before the great common-js-helpers move
+  OT.Modal = OT.$.Modal;
+
+  // Add logging methods
+  OT.$.useLogHelpers(OT);
+
+  var _debugHeaderLogged = false,
+      _setLogLevel = OT.setLogLevel;
+
+  // On the first time log level is set to DEBUG (or higher) show version info.
+  OT.setLogLevel = function(level) {
+    // Set OT.$ to the same log level
+    OT.$.setLogLevel(level);
+    var retVal = _setLogLevel.call(OT, level);
+    if (OT.shouldLog(OT.DEBUG) && !_debugHeaderLogged) {
+      OT.debug('OpenTok JavaScript library ' + OT.properties.version);
+      OT.debug('Release notes: ' + OT.properties.websiteURL +
+        '/opentok/webrtc/docs/js/release-notes.html');
+      OT.debug('Known issues: ' + OT.properties.websiteURL +
+        '/opentok/webrtc/docs/js/release-notes.html#knownIssues');
+      _debugHeaderLogged = true;
+    }
+    OT.debug('OT.setLogLevel(' + retVal + ')');
+    return retVal;
+  };
+
+  OT.setLogLevel(OT.properties.debug ? OT.DEBUG : OT.ERROR);
+
+  /**
+  * Sets the API log level.
+  * <p>
+  * Calling <code>OT.setLogLevel()</code> sets the log level for runtime log messages that
+  * are the OpenTok library generates. The default value for the log level is <code>OT.ERROR</code>.
+  * </p>
+  * <p>
+  * The OpenTok JavaScript library displays log messages in the debugger console (such as
+  * Firebug), if one exists.
+  * </p>
+  * <p>
+  * The following example logs the session ID to the console, by calling <code>OT.log()</code>.
+  * The code also logs an error message when it attempts to publish a stream before the Session
+  * object dispatches a <code>sessionConnected</code> event.
+  * </p>
+  * <pre>
+  * OT.setLogLevel(OT.LOG);
+  * session = OT.initSession(sessionId);
+  * OT.log(sessionId);
+  * publisher = OT.initPublisher("publishContainer");
+  * session.publish(publisher);
+  * </pre>
+  *
+  * @param {Number} logLevel The degree of logging desired by the developer:
+  *
+  * <p>
+  * <ul>
+  *   <li>
+  *     <code>OT.NONE</code> &#151; API logging is disabled.
+  *   </li>
+  *   <li>
+  *     <code>OT.ERROR</code> &#151; Logging of errors only.
+  *   </li>
+  *   <li>
+  *     <code>OT.WARN</code> &#151; Logging of warnings and errors.
+  *   </li>
+  *   <li>
+  *     <code>OT.INFO</code> &#151; Logging of other useful information, in addition to
+  *     warnings and errors.
+  *   </li>
+  *   <li>
+  *     <code>OT.LOG</code> &#151; Logging of <code>OT.log()</code> messages, in addition
+  *     to OpenTok info, warning,
+  *     and error messages.
+  *   </li>
+  *   <li>
+  *     <code>OT.DEBUG</code> &#151; Fine-grained logging of all API actions, as well as
+  *     <code>OT.log()</code> messages.
+  *   </li>
+  * </ul>
+  * </p>
+  *
+  * @name OT.setLogLevel
+  * @memberof OT
+  * @function
+  * @see <a href="#log">OT.log()</a>
+  */
+
+  /**
+  * Sends a string to the the debugger console (such as Firebug), if one exists.
+  * However, the function only logs to the console if you have set the log level
+  * to <code>OT.LOG</code> or <code>OT.DEBUG</code>,
+  * by calling <code>OT.setLogLevel(OT.LOG)</code> or <code>OT.setLogLevel(OT.DEBUG)</code>.
+  *
+  * @param {String} message The string to log.