Bug 1223573 - Part 5. Update uris and paths for files in Loop's system add-on. r=mikedeboer
authorMark Banner <standard8@mozilla.com>
Sun, 29 Nov 2015 17:08:35 +0000
changeset 274522 e19308d96a1dc85718eef8999ad86b7e35223d5c
parent 274521 de0a9431b7c7e584bb0fa83b1d1c6d96dfc99e21
child 274523 117061bb2218b158627a4182742c0cb0598edd3e
push id29733
push usercbook@mozilla.com
push dateMon, 30 Nov 2015 12:16:19 +0000
treeherdermozilla-central@2d385f1302a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1223573
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1223573 - Part 5. Update uris and paths for files in Loop's system add-on. r=mikedeboer
browser/components/uitour/test/browser_UITour_loop.js
browser/extensions/loop/README.txt
browser/extensions/loop/bootstrap.js
browser/extensions/loop/build-jsx
browser/extensions/loop/content/modules/LoopRooms.jsm
browser/extensions/loop/content/modules/LoopRoomsCache.jsm
browser/extensions/loop/content/modules/MozLoopAPI.jsm
browser/extensions/loop/content/modules/MozLoopPushHandler.jsm
browser/extensions/loop/content/modules/MozLoopService.jsm
browser/extensions/loop/content/panels/conversation.html
browser/extensions/loop/content/panels/css/panel.css
browser/extensions/loop/content/panels/js/panel.js
browser/extensions/loop/content/panels/js/panel.jsx
browser/extensions/loop/content/panels/js/roomViews.js
browser/extensions/loop/content/panels/js/roomViews.jsx
browser/extensions/loop/content/panels/panel.html
browser/extensions/loop/content/shared/css/conversation.css
browser/extensions/loop/content/shared/js/crypto.js
browser/extensions/loop/content/shared/js/views.js
browser/extensions/loop/content/shared/js/views.jsx
browser/extensions/loop/moz.build
browser/extensions/loop/skin/shared/loop.css
browser/extensions/loop/skin/windows/platform.css
browser/extensions/loop/standalone/content/css/webapp.css
browser/extensions/loop/standalone/content/webappEntryPoint.js
browser/extensions/loop/standalone/server.js
browser/extensions/loop/test/desktop-local/README.md
browser/extensions/loop/test/desktop-local/index.html
browser/extensions/loop/test/karma/karma.coverage.desktop.js
browser/extensions/loop/test/karma/karma.coverage.shared_standalone.js
browser/extensions/loop/test/mochitest/browser_LoopRooms_channel.js
browser/extensions/loop/test/mochitest/browser_fxa_login.js
browser/extensions/loop/test/mochitest/browser_loop_fxa_server.js
browser/extensions/loop/test/mochitest/browser_mozLoop_appVersionInfo.js
browser/extensions/loop/test/mochitest/browser_mozLoop_context.js
browser/extensions/loop/test/mochitest/browser_mozLoop_sharingListeners.js
browser/extensions/loop/test/mochitest/browser_mozLoop_socialShare.js
browser/extensions/loop/test/mochitest/browser_mozLoop_telemetry.js
browser/extensions/loop/test/mochitest/browser_toolbarbutton.js
browser/extensions/loop/test/mochitest/head.js
browser/extensions/loop/test/shared/index.html
browser/extensions/loop/test/shared/views_test.js
browser/extensions/loop/test/standalone/index.html
browser/extensions/loop/test/xpcshell/.eslintrc
browser/extensions/loop/test/xpcshell/head.js
browser/extensions/loop/test/xpcshell/test_loopapi_doNotDisturb.js
browser/extensions/loop/test/xpcshell/test_loopapi_internal.js
browser/extensions/loop/test/xpcshell/test_loopapi_prefs.js
browser/extensions/loop/test/xpcshell/test_looprooms.js
browser/extensions/loop/test/xpcshell/test_looprooms_encryption_in_fxa.js
browser/extensions/loop/test/xpcshell/test_looprooms_first_notification.js
browser/extensions/loop/test/xpcshell/test_looprooms_getall.js
browser/extensions/loop/test/xpcshell/test_looprooms_upgrade_to_encryption.js
browser/extensions/loop/test/xpcshell/test_loopservice_hawk_errors.js
browser/extensions/loop/ui/README.md
browser/extensions/loop/ui/index.html
--- a/browser/components/uitour/test/browser_UITour_loop.js
+++ b/browser/components/uitour/test/browser_UITour_loop.js
@@ -4,18 +4,18 @@
 "use strict";
 
 var gTestTab;
 var gContentAPI;
 var gContentWindow;
 var loopButton;
 var loopPanel = document.getElementById("loop-notification-panel");
 
-const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
-const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+const { LoopRooms } = Components.utils.import("chrome://loop/content/modules/LoopRooms.jsm", {});
+const { MozLoopServiceInternal } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
 
 function test() {
   UITourTest();
 }
 
 function runOffline(fun) {
   return (done) => {
     Services.io.offline = true;
--- a/browser/extensions/loop/README.txt
+++ b/browser/extensions/loop/README.txt
@@ -17,47 +17,47 @@ Working with React JSX files
 
 Our views use [React](http://facebook.github.io/react/) written in JSX files
 and transpiled to JS before we commit. You need to install the JSX compiler
 using npm in order to compile the .jsx files into regular .js ones:
 
     npm install -g react-tools@0.12.2
 
 Once installed, run build-jsx with the --watch option from
-browser/components/loop, eg.:
+browser/extensions/loop, eg.:
 
-    cd browser/components/loop
+    cd browser/extensions/loop
     ./build-jsx --watch
 
 build-jsx can also be do a one-time compile pass instead of watching if
 the --watch argument is omitted.  Be sure to commit any transpiled files
 at the same time as changes to their sources.
 
 
 Hacking
 =======
 Please be sure to execute
 
-  browser/components/loop/run-all-loop-tests.sh
+  browser/extensions/loop/run-all-loop-tests.sh
 
 from the top level before requesting review on a patch.
 
 Linting
 =======
 run-all-loop-tests.sh will take care of this for you automatically, after
 you've installed the dependencies by typing:
 
   ( cd standalone ; make install )
 
 If you install eslint and the react plugin globally:
 
   npm install -g eslint
   npm install -g eslint-plugin-react
 
-You can also run it by hand in the browser/components/loop directory:
+You can also run it by hand in the browser/extensions/loop directory:
 
   eslint --ext .js --ext .jsx --ext .jsm .
 
 Test coverage
 =============
 Initial setup
   cd test
   npm install
@@ -83,17 +83,17 @@ You can run these as part of the run-all
 Functional Tests
 ================
 These are currently a work in progress, but it's already possible to run a test
 if you have a [loop-server](https://github.com/mozilla-services/loop-server)
 install that is properly configured.  From the top-level gecko directory,
 execute:
 
   export LOOP_SERVER=/Users/larry/src/loop-server
-  ./mach marionette-test browser/components/loop/test/functional/manifest.ini
+  ./mach marionette-test browser/extensions/loop/test/functional/manifest.ini
 
 Once the automation is complete, we'll include this in run-all-loop-tests.sh
 as well.
 
 
 UI-Showcase
 ===========
 This is a tool giving the layouts for all the frontend views of Loop, allowing debugging and testing of css layouts and local component behavior.
--- a/browser/extensions/loop/bootstrap.js
+++ b/browser/extensions/loop/bootstrap.js
@@ -404,17 +404,17 @@ var WindowListener = {
        * @param {String} name Name of the sound, like 'ringtone' or 'room-joined'
        */
       playSound: function(name) {
         if (this.ActiveSound || this.MozLoopService.doNotDisturb) {
           return;
         }
 
         this.activeSound = new window.Audio();
-        this.activeSound.src = `chrome://browser/content/loop/shared/sounds/${name}.ogg`;
+        this.activeSound.src = `chrome://loop/content/shared/sounds/${name}.ogg`;
         this.activeSound.load();
         this.activeSound.play();
 
         this.activeSound.addEventListener("ended", () => this.activeSound = undefined, false);
       },
 
       /**
        * Start listening to selected tab changes and notify any content page that's
@@ -605,15 +605,15 @@ var WindowListener = {
           xhr.send();
         }).catch(err => {
           callback(err || new Error("No favicon found"));
         });
       }
     };
 
     XPCOMUtils.defineLazyModuleGetter(LoopUI, "hookWindowCloseForPanelClose", "resource://gre/modules/MozSocialAPI.jsm");
-    XPCOMUtils.defineLazyModuleGetter(LoopUI, "LoopAPI", "resource:///modules/loop/MozLoopAPI.jsm");
-    XPCOMUtils.defineLazyModuleGetter(LoopUI, "LoopRooms", "resource:///modules/loop/LoopRooms.jsm");
-    XPCOMUtils.defineLazyModuleGetter(LoopUI, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm");
+    XPCOMUtils.defineLazyModuleGetter(LoopUI, "LoopAPI", "chrome://loop/content/modules/MozLoopAPI.jsm");
+    XPCOMUtils.defineLazyModuleGetter(LoopUI, "LoopRooms", "chrome://loop/content/modules/LoopRooms.jsm");
+    XPCOMUtils.defineLazyModuleGetter(LoopUI, "MozLoopService", "chrome://loop/content/modules/MozLoopService.jsm");
     XPCOMUtils.defineLazyModuleGetter(LoopUI, "PanelFrame", "resource:///modules/PanelFrame.jsm");
     XPCOMUtils.defineLazyModuleGetter(LoopUI, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
   }
 }
--- a/browser/extensions/loop/build-jsx
+++ b/browser/extensions/loop/build-jsx
@@ -69,17 +69,17 @@ def find_react_command():
 
     # This is what node really wants to run.
     jsx_path = os.path.join(jsx_path,
                             "node_modules", "react-tools", "bin", "jsx")
 
     return [node, jsx_path]
 
 
-SHARED_LIBS_DIR=os.path.join(os.path.dirname(__file__), "content", "shared", "libs")
+SHARED_LIBS_DIR=os.path.join(os.path.dirname(__file__), "content", "shared", "vendor")
 REACT_VERSION=find_react_version(SHARED_LIBS_DIR)
 
 src_files = []  # files to be compiled
 
 run_command = find_react_command()
 
 if sys.platform == 'win32':
     print 'Please ensure you are running react-tools version %s' % REACT_VERSION
@@ -94,17 +94,17 @@ else:
     if not info == REACT_VERSION:
         print 'You have the wrong version of react-tools installed'
         print 'Please use version %s' % REACT_VERSION
         exit(1)
 
 # parse the CLI arguments
 description = 'Loop build tool for JSX files. ' + \
               'Will scan entire loop directory and compile them in place. ' + \
-              'Must be executed from browser/components/loop directory.'
+              'Must be executed from browser/extensions/loop directory.'
 
 parser = argparse.ArgumentParser(description=description)
 parser.add_argument('--watch', '-w', action='store_true', help='continuous' +
                     'build based on file changes (optional)')
 args = parser.parse_args()
 
 # loop through all tuples and get unique dirs only
 unique_jsx_dirs = []
--- a/browser/extensions/loop/content/modules/LoopRooms.jsm
+++ b/browser/extensions/loop/content/modules/LoopRooms.jsm
@@ -5,38 +5,38 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 
-const { MozLoopService, LOOP_SESSION_TYPE } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+const { MozLoopService, LOOP_SESSION_TYPE } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
                                   "resource://services-common/utils.js");
 XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
                                   "resource://gre/modules/WebChannel.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
   const { EventEmitter } = Cu.import("resource://devtools/shared/event-emitter.js", {});
   return new EventEmitter();
 });
 XPCOMUtils.defineLazyGetter(this, "gLoopBundle", function() {
   return Services.strings.createBundle("chrome://browser/locale/loop/loop.properties");
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoopRoomsCache",
-  "resource:///modules/loop/LoopRoomsCache.jsm");
+  "chrome://loop/content/modules/LoopRoomsCache.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "loopUtils",
-  "resource:///modules/loop/utils.js", "utils");
+  "chrome://loop/content/modules/utils.js", "utils");
 XPCOMUtils.defineLazyModuleGetter(this, "loopCrypto",
-  "resource:///modules/loop/crypto.js", "LoopCrypto");
+  "chrome://loop/content/shared/js/crypto.js", "LoopCrypto");
 XPCOMUtils.defineLazyModuleGetter(this, "ObjectUtils",
   "resource://gre/modules/ObjectUtils.jsm");
 
 
 this.EXPORTED_SYMBOLS = ["LoopRooms", "roomsPushNotification"];
 
 // The maximum number of clients that we support currently.
 const CLIENT_MAX_SIZE = 2;
--- a/browser/extensions/loop/content/modules/LoopRoomsCache.jsm
+++ b/browser/extensions/loop/content/modules/LoopRoomsCache.jsm
@@ -4,17 +4,17 @@
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 const { MozLoopService, LOOP_SESSION_TYPE } =
-  Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+  Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
                                   "resource://services-common/utils.js");
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 
 this.EXPORTED_SYMBOLS = ["LoopRoomsCache"];
 
 const LOOP_ROOMS_CACHE_FILENAME = "loopRoomsCache.json";
 XPCOMUtils.defineConstant(this, "LOOP_ROOMS_CACHE_FILENAME", LOOP_ROOMS_CACHE_FILENAME);
--- a/browser/extensions/loop/content/modules/MozLoopAPI.jsm
+++ b/browser/extensions/loop/content/modules/MozLoopAPI.jsm
@@ -4,18 +4,18 @@
 
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/loop/MozLoopService.jsm");
-Cu.import("resource:///modules/loop/LoopRooms.jsm");
+Cu.import("chrome://loop/content/modules/MozLoopService.jsm");
+Cu.import("chrome://loop/content/modules/LoopRooms.jsm");
 Cu.importGlobalProperties(["Blob"]);
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata",
                                         "resource://gre/modules/PageMetadata.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                         "resource://gre/modules/PluralForm.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                         "resource://gre/modules/UpdateUtils.jsm");
--- a/browser/extensions/loop/content/modules/MozLoopPushHandler.jsm
+++ b/browser/extensions/loop/content/modules/MozLoopPushHandler.jsm
@@ -5,17 +5,17 @@
 "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/Timer.jsm");
 
-const { MozLoopService } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+const { MozLoopService } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
 const consoleLog = MozLoopService.log;
 
 this.EXPORTED_SYMBOLS = ["MozLoopPushHandler"];
 
 const CONNECTION_STATE_CLOSED = 0;
 const CONNECTION_STATE_CONNECTING = 1;
 const CONNECTION_STATE_OPEN = 2;
 
--- a/browser/extensions/loop/content/modules/MozLoopService.jsm
+++ b/browser/extensions/loop/content/modules/MozLoopService.jsm
@@ -116,24 +116,24 @@ XPCOMUtils.defineConstant(this, "LOOP_SE
 XPCOMUtils.defineConstant(this, "TWO_WAY_MEDIA_CONN_LENGTH", TWO_WAY_MEDIA_CONN_LENGTH);
 XPCOMUtils.defineConstant(this, "SHARING_STATE_CHANGE", SHARING_STATE_CHANGE);
 XPCOMUtils.defineConstant(this, "SHARING_ROOM_URL", SHARING_ROOM_URL);
 XPCOMUtils.defineConstant(this, "ROOM_CREATE", ROOM_CREATE);
 XPCOMUtils.defineConstant(this, "ROOM_DELETE", ROOM_DELETE);
 XPCOMUtils.defineConstant(this, "ROOM_CONTEXT_ADD", ROOM_CONTEXT_ADD);
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoopAPI",
-  "resource:///modules/loop/MozLoopAPI.jsm");
+  "chrome://loop/content/modules/MozLoopAPI.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport",
   "resource://gre/modules/media/RTCStatsReport.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "loopUtils",
-  "resource:///modules/loop/utils.js", "utils");
+  "chrome://loop/content/modules/utils.js", "utils");
 XPCOMUtils.defineLazyModuleGetter(this, "loopCrypto",
-  "resource:///modules/loop/crypto.js", "LoopCrypto");
+  "chrome://loop/content/shared/js/crypto.js", "LoopCrypto");
 
 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");
@@ -146,23 +146,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyModuleGetter(this, "deriveHawkCredentials",
                                   "resource://services-common/hawkrequest.js");
 
 XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
                                   "resource://gre/modules/MozSocialAPI.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoopRooms",
-                                  "resource:///modules/loop/LoopRooms.jsm");
+                                  "chrome://loop/content/modules/LoopRooms.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "roomsPushNotification",
-                                  "resource:///modules/loop/LoopRooms.jsm");
+                                  "chrome://loop/content/modules/LoopRooms.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
-                                  "resource:///modules/loop/MozLoopPushHandler.jsm");
+                                  "chrome://loop/content/modules/MozLoopPushHandler.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "UITour",
                                   "resource:///modules/UITour.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
--- a/browser/extensions/loop/content/panels/conversation.html
+++ b/browser/extensions/loop/content/panels/conversation.html
@@ -2,47 +2,48 @@
 <!-- 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 is set in conversation.js -->
     <title></title>
-    <link rel="stylesheet" type="text/css" href="loop/shared/css/reset.css">
-    <link rel="stylesheet" type="text/css" href="loop/shared/css/common.css">
-    <link rel="stylesheet" type="text/css" href="loop/shared/css/conversation.css">
+    <base href="chrome://loop/content">
+    <link rel="stylesheet" type="text/css" href="shared/css/reset.css">
+    <link rel="stylesheet" type="text/css" href="shared/css/common.css">
+    <link rel="stylesheet" type="text/css" href="shared/css/conversation.css">
  </head>
   <body class="fx-embedded">
 
     <div id="messages"></div>
 
     <div id="main"></div>
 
-    <script type="text/javascript" src="loop/libs/l10n.js"></script>
-    <script type="text/javascript" src="loop/js/otconfig.js"></script>
-    <script type="text/javascript" src="loop/libs/sdk.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/react-0.13.3.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/lodash-3.9.3.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/backbone-1.2.1.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/classnames-2.2.0.js"></script>
+    <script type="text/javascript" src="panels/vendor/l10n.js"></script>
+    <script type="text/javascript" src="panels/js/otconfig.js"></script>
+    <script type="text/javascript" src="shared/vendor/sdk.js"></script>
+    <script type="text/javascript" src="shared/vendor/react-0.13.3.js"></script>
+    <script type="text/javascript" src="shared/vendor/lodash-3.9.3.js"></script>
+    <script type="text/javascript" src="shared/vendor/backbone-1.2.1.js"></script>
+    <script type="text/javascript" src="shared/vendor/classnames-2.2.0.js"></script>
 
-    <script type="text/javascript" src="loop/shared/js/loopapi-client.js"></script>
-    <script type="text/javascript" src="loop/shared/js/utils.js"></script>
-    <script type="text/javascript" src="loop/shared/js/mixins.js"></script>
-    <script type="text/javascript" src="loop/shared/js/actions.js"></script>
-    <script type="text/javascript" src="loop/shared/js/validate.js"></script>
-    <script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
-    <script type="text/javascript" src="loop/shared/js/otSdkDriver.js"></script>
-    <script type="text/javascript" src="loop/shared/js/store.js"></script>
-    <script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
-    <script type="text/javascript" src="loop/shared/js/views.js"></script>
-    <script type="text/javascript" src="loop/js/feedbackViews.js"></script>
-    <script type="text/javascript" src="loop/shared/js/textChatStore.js"></script>
-    <script type="text/javascript" src="loop/shared/js/textChatView.js"></script>
-    <script type="text/javascript" src="loop/shared/js/linkifiedTextView.js"></script>
-    <script type="text/javascript" src="loop/shared/js/urlRegExps.js"></script>
-    <script type="text/javascript" src="loop/js/conversationAppStore.js"></script>
-    <script type="text/javascript" src="loop/js/roomStore.js"></script>
-    <script type="text/javascript" src="loop/js/roomViews.js"></script>
-    <script type="text/javascript" src="loop/js/conversation.js"></script>
+    <script type="text/javascript" src="shared/js/loopapi-client.js"></script>
+    <script type="text/javascript" src="shared/js/utils.js"></script>
+    <script type="text/javascript" src="shared/js/mixins.js"></script>
+    <script type="text/javascript" src="shared/js/actions.js"></script>
+    <script type="text/javascript" src="shared/js/validate.js"></script>
+    <script type="text/javascript" src="shared/js/dispatcher.js"></script>
+    <script type="text/javascript" src="shared/js/otSdkDriver.js"></script>
+    <script type="text/javascript" src="shared/js/store.js"></script>
+    <script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
+    <script type="text/javascript" src="shared/js/views.js"></script>
+    <script type="text/javascript" src="shared/js/textChatStore.js"></script>
+    <script type="text/javascript" src="shared/js/textChatView.js"></script>
+    <script type="text/javascript" src="shared/js/linkifiedTextView.js"></script>
+    <script type="text/javascript" src="shared/js/urlRegExps.js"></script>
+    <script type="text/javascript" src="panels/js/conversationAppStore.js"></script>
+    <script type="text/javascript" src="panels/js/feedbackViews.js"></script>
+    <script type="text/javascript" src="panels/js/roomStore.js"></script>
+    <script type="text/javascript" src="panels/js/roomViews.js"></script>
+    <script type="text/javascript" src="panels/js/conversation.js"></script>
   </body>
 </html>
--- a/browser/extensions/loop/content/panels/css/panel.css
+++ b/browser/extensions/loop/content/panels/css/panel.css
@@ -7,17 +7,17 @@ html {
 }
 
 body {
   background: none;
 }
 
 /* Beta Ribbon */
 .beta-ribbon {
-  background: url("../shared/img/beta-ribbon.svg") no-repeat;
+  background: url("../../shared/img/beta-ribbon.svg") no-repeat;
   background-size: 30px;
   width: 30px;
   height: 30px;
 }
 
 /* Panel styles */
 
 .panel {
@@ -153,17 +153,17 @@ body {
   text-align: center;
   color: #4a4a4a;
   font-weight: lighter;
   position: relative;
   top: 50%;
   transform: translateY(-50%);
   padding-top: 11rem;
   padding-bottom: 1rem;
-  background-image: url("../shared/img/empty_conversations.svg");
+  background-image: url("../../shared/img/empty_conversations.svg");
   background-repeat: no-repeat;
   background-position: top center;
 }
 
 .panel-text-medium,
 .panel-text-large {
   margin: 3px 0;
 }
@@ -319,31 +319,31 @@ body {
 }
 
 .room-list > .room-entry:hover > h2 > button {
   animation: drop-and-fade-in 0.250s;
   animation-fill-mode: forwards;
 }
 
 .room-list > .room-entry:hover > h2 > .copy-link {
-  background-image: url(../shared/img/icons-16x16.svg#copy);
+  background-image: url(../../shared/img/icons-16x16.svg#copy);
 }
 
 .room-list > .room-entry:hover > h2 > .delete-link {
-  background-image: url(../shared/img/icons-16x16.svg#trash);
+  background-image: url(../../shared/img/icons-16x16.svg#trash);
 }
 
 /* scale this up to 1.1x and then back to the original size */
 @keyframes pulse {
   0%, 100% { transform: scale(1.0); }
   50%      { transform: scale(1.1); }
 }
 
 .room-list > .room-entry > h2 > .copy-link.checked {
-  background: transparent url(../shared/img/icons-16x16.svg#checkmark);
+  background: transparent url(../../shared/img/icons-16x16.svg#checkmark);
   animation: pulse .150s;
   animation-timing-function: ease-in-out;
   top: 0;
 }
 
 /* keep the various room-entry row pieces aligned with each other */
 .room-list > .room-entry > h2 > button,
 .room-list > .room-entry > h2 > span {
@@ -357,17 +357,17 @@ body {
 }
 
 .room-entry:hover .room-entry-context-actions {
   display: inline-block;
 }
 
 /* Room entry edit button */
 .room-entry-context-edit-btn {
-  background-image: url("../shared/img/icons-10x10.svg#edit-darkgrey");
+  background-image: url("../../shared/img/icons-10x10.svg#edit-darkgrey");
   background-position: center;
   background-repeat: no-repeat;
   background-size: 12px;
   cursor: pointer;
   display: inline-block;
   height: 24px;
   vertical-align: middle;
   width: 16px;
@@ -394,17 +394,17 @@ html[dir="rtl"] .room-entry-context-acti
 
 .room-entry-context-item > img,
 .room-entry-context-item > a > img {
   width: 16px;
 }
 
 .button-close {
   background-color: transparent;
-  background-image: url(../shared/img/icons-10x10.svg#close);
+  background-image: url(../../shared/img/icons-10x10.svg#close);
   background-repeat: no-repeat;
   background-size: 8px 8px;
   border: none;
   padding: 0;
   height: 8px;
   width: 8px;
 }
 
@@ -423,26 +423,26 @@ html[dir="rtl"] .room-entry-context-acti
 .spinner {
   width: 16px;
   height: 16px;
   background-repeat: no-repeat;
   background-size: 16px 16px;
 }
 
 .spinner.busy {
-  background-image: url(../shared/img/spinner.png);
+  background-image: url(../../shared/img/spinner.png);
   animation-name: spinnerRotate;
   animation-duration: 1s;
   animation-timing-function: linear;
   animation-iteration-count: infinite;
 }
 
 @media (min-resolution: 2dppx) {
   .spinner.busy {
-    background-image: url(../shared/img/spinner@2x.png);
+    background-image: url(../../shared/img/spinner@2x.png);
   }
 }
 
 /* Share tab */
 
 .generate-url-stack {
   margin: 14px 0;
   position: relative;
@@ -497,60 +497,60 @@ html[dir="rtl"] .generate-url-spinner {
   margin-top: 0;
 }
 
 #powered-by-logo {
   display: inline-block;
   margin-left: 10px;
   margin-right: 10px;
   vertical-align: middle;
-  background-image: url("../shared/img/telefonica.png");
+  background-image: url("../../shared/img/telefonica.png");
   background-size: 72px 20px;
   width: 72px;
   height: 20px;
 }
 
 #powered-by-logo.en-GB,
 #powered-by-logo.de {
-  background-image: url("../shared/img/02.png");
+  background-image: url("../../shared/img/02.png");
   background-size: 21px 20px;
   width: 21px;
   height: 20px;
 }
 
 #powered-by-logo.pt-BR {
-  background-image: url("../shared/img/vivo.png");
+  background-image: url("../../shared/img/vivo.png");
   background-size: 53px 26px;
   width: 53px;
   height: 26px;
 }
 
 #powered-by-logo[class^="es-"] {
-  background-image: url("../shared/img/movistar.png");
+  background-image: url("../../shared/img/movistar.png");
   background-size: 92px 20px;
   width: 92px;
   height: 20px;
 }
 
 @media (min-resolution: 2dppx) {
   #powered-by-logo {
-    background-image: url("../shared/img/telefonica@2x.png");
+    background-image: url("../../shared/img/telefonica@2x.png");
   }
 
   #powered-by-logo.en-GB,
   #powered-by-logo.de {
-    background-image: url("../shared/img/02@2x.png");
+    background-image: url("../../shared/img/02@2x.png");
   }
 
   #powered-by-logo.pt-BR {
-    background-image: url("../shared/img/vivo@2x.png");
+    background-image: url("../../shared/img/vivo@2x.png");
   }
 
   #powered-by-logo[class^="es-"] {
-    background-image: url("../shared/img/movistar@2x.png");
+    background-image: url("../../shared/img/movistar@2x.png");
   }
 }
 
 .terms-service {
   padding-left: 5rem;
   padding-right: 5rem;
   padding-bottom: 1rem;
   text-align: center;
@@ -589,17 +589,17 @@ html[dir="rtl"] .generate-url-spinner {
 .button-settings {
   width: 10px;
   height: 10px;
   margin: 0;
   padding: 0;
   border: none;
   cursor: pointer;
   vertical-align: middle;
-  background: transparent url("../shared/img/icons-10x10.svg#settings-cog");
+  background: transparent url("../../shared/img/icons-10x10.svg#settings-cog");
   background-position: center;
   background-repeat: no-repeat;
   background-size: cover;
   -moz-margin-start: .5em;
 }
 
 .user-details .dropdown-menu {
   bottom: 1.3rem; /* Just above the text. */
--- a/browser/extensions/loop/content/panels/js/panel.js
+++ b/browser/extensions/loop/content/panels/js/panel.js
@@ -24,17 +24,17 @@ loop.panel = (function(_, mozL10n) {
       window.dispatchEvent(event);
       this.closeWindow();
     },
 
     render: function() {
       return (
         React.createElement("div", {className: "fte-get-started-content"}, 
           React.createElement("header", {className: "fte-title"}, 
-            React.createElement("img", {src: "loop/shared/img/hello_logo.svg"}), 
+            React.createElement("img", {src: "shared/img/hello_logo.svg"}), 
             React.createElement("div", {className: "fte-subheader"}, 
               mozL10n.get("first_time_experience_subheading")
             )
           ), 
           React.createElement(Button, {additionalClass: "fte-get-started-button", 
                   caption: mozL10n.get("first_time_experience_button_label"), 
                   htmlId: "fte-button", 
                   onClick: this.handleButtonClick})
@@ -374,28 +374,28 @@ loop.panel = (function(_, mozL10n) {
         loop.request("OpenURL", event.currentTarget.href);
         this.closeWindow();
       }
     },
 
     _renderDefaultIcon: function() {
       return (
         React.createElement("div", {className: "room-entry-context-item"}, 
-          React.createElement("img", {src: "loop/shared/img/icons-16x16.svg#globe"})
+          React.createElement("img", {src: "shared/img/icons-16x16.svg#globe"})
         )
       );
     },
 
     _renderIcon: function(roomUrl) {
       return (
         React.createElement("div", {className: "room-entry-context-item"}, 
           React.createElement("a", {href: roomUrl.location, 
             onClick: this.handleClick, 
             title: roomUrl.description}, 
-            React.createElement("img", {src: roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"})
+            React.createElement("img", {src: roomUrl.thumbnail || "shared/img/icons-16x16.svg#globe"})
           )
         )
       );
     },
 
     render: function() {
       var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
       if (roomUrl && roomUrl.location) {
@@ -712,17 +712,17 @@ loop.panel = (function(_, mozL10n) {
      * Let the user know we're loading rooms
      * @returns {Object} React render
      */
     _renderLoadingRoomsView: function() {
       return (
         React.createElement("div", {className: "room-list"}, 
           this._renderNewRoomButton(), 
           React.createElement("div", {className: "room-list-loading"}, 
-            React.createElement("img", {src: "loop/shared/img/animated-spinner.svg"})
+            React.createElement("img", {src: "shared/img/animated-spinner.svg"})
           )
         )
       );
     },
 
     _renderNoRoomsView: function() {
       return (
         React.createElement("div", {className: "rooms"}, 
@@ -879,17 +879,17 @@ loop.panel = (function(_, mozL10n) {
     propTypes: {
       onClick: React.PropTypes.func.isRequired
     },
 
     render: function() {
       return (
         React.createElement("div", {className: "error-content"}, 
           React.createElement("header", {className: "error-title"}, 
-            React.createElement("img", {src: "loop/shared/img/sad_hello_icon_64x64.svg"}), 
+            React.createElement("img", {src: "shared/img/sad_hello_icon_64x64.svg"}), 
             React.createElement("p", {className: "error-subheader"}, 
               mozL10n.get("e10s_not_supported_subheading", {
                 brandShortname: mozL10n.get("clientShortname2")
               })
             )
           ), 
           React.createElement(Button, {additionalClass: "e10s-not-supported-button", 
                   caption: mozL10n.get("e10s_not_supported_button_label"), 
--- a/browser/extensions/loop/content/panels/js/panel.jsx
+++ b/browser/extensions/loop/content/panels/js/panel.jsx
@@ -24,17 +24,17 @@ loop.panel = (function(_, mozL10n) {
       window.dispatchEvent(event);
       this.closeWindow();
     },
 
     render: function() {
       return (
         <div className="fte-get-started-content">
           <header className="fte-title">
-            <img src="loop/shared/img/hello_logo.svg" />
+            <img src="shared/img/hello_logo.svg" />
             <div className="fte-subheader">
               {mozL10n.get("first_time_experience_subheading")}
             </div>
           </header>
           <Button additionalClass="fte-get-started-button"
                   caption={mozL10n.get("first_time_experience_button_label")}
                   htmlId="fte-button"
                   onClick={this.handleButtonClick} />
@@ -374,28 +374,28 @@ loop.panel = (function(_, mozL10n) {
         loop.request("OpenURL", event.currentTarget.href);
         this.closeWindow();
       }
     },
 
     _renderDefaultIcon: function() {
       return (
         <div className="room-entry-context-item">
-          <img src="loop/shared/img/icons-16x16.svg#globe" />
+          <img src="shared/img/icons-16x16.svg#globe" />
         </div>
       );
     },
 
     _renderIcon: function(roomUrl) {
       return (
         <div className="room-entry-context-item">
           <a href={roomUrl.location}
             onClick={this.handleClick}
             title={roomUrl.description}>
-            <img src={roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"} />
+            <img src={roomUrl.thumbnail || "shared/img/icons-16x16.svg#globe"} />
           </a>
         </div>
       );
     },
 
     render: function() {
       var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
       if (roomUrl && roomUrl.location) {
@@ -712,17 +712,17 @@ loop.panel = (function(_, mozL10n) {
      * Let the user know we're loading rooms
      * @returns {Object} React render
      */
     _renderLoadingRoomsView: function() {
       return (
         <div className="room-list">
           {this._renderNewRoomButton()}
           <div className="room-list-loading">
-            <img src="loop/shared/img/animated-spinner.svg" />
+            <img src="shared/img/animated-spinner.svg" />
           </div>
         </div>
       );
     },
 
     _renderNoRoomsView: function() {
       return (
         <div className="rooms">
@@ -879,17 +879,17 @@ loop.panel = (function(_, mozL10n) {
     propTypes: {
       onClick: React.PropTypes.func.isRequired
     },
 
     render: function() {
       return (
         <div className="error-content">
           <header className="error-title">
-            <img src="loop/shared/img/sad_hello_icon_64x64.svg" />
+            <img src="shared/img/sad_hello_icon_64x64.svg" />
             <p className="error-subheader">
               {mozL10n.get("e10s_not_supported_subheading", {
                 brandShortname: mozL10n.get("clientShortname2")
               })}
             </p>
           </header>
           <Button additionalClass="e10s-not-supported-button"
                   caption={mozL10n.get("e10s_not_supported_button_label")}
--- a/browser/extensions/loop/content/panels/js/roomViews.js
+++ b/browser/extensions/loop/content/panels/js/roomViews.js
@@ -341,24 +341,24 @@ loop.roomViews = (function(mozL10n) {
             hide: this.props.showEditContext
           })}, 
             React.createElement("div", {className: cx({
                 "btn-copy": true,
                 "invite-button": true,
                 "triggered": this.state.copiedUrl
               }), 
               onClick: this.handleCopyButtonClick}, 
-              React.createElement("img", {src: "loop/shared/img/svg/glyph-link-16x16.svg"}), 
+              React.createElement("img", {src: "shared/img/glyph-link-16x16.svg"}), 
               React.createElement("p", null, mozL10n.get(this.state.copiedUrl ?
                 "invite_copied_link_button" : "invite_copy_link_button"))
             ), 
             React.createElement("div", {className: "btn-email invite-button", 
               onClick: this.handleEmailButtonClick, 
               onMouseOver: this.resetTriggeredButtons}, 
-              React.createElement("img", {src: "loop/shared/img/svg/glyph-email-16x16.svg"}), 
+              React.createElement("img", {src: "shared/img/glyph-email-16x16.svg"}), 
               React.createElement("p", null, mozL10n.get("invite_email_link_button"))
             )
           ), 
           React.createElement(SocialShareDropdown, {
             dispatcher: this.props.dispatcher, 
             ref: "menu", 
             roomUrl: this.props.roomData.roomUrl, 
             show: this.state.showMenu, 
@@ -531,17 +531,17 @@ loop.roomViews = (function(mozL10n) {
     },
 
     render: function() {
       if (!this.state.show) {
         return null;
       }
 
       var url = this._getURL();
-      var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
+      var thumbnail = url && url.thumbnail || "shared/img/icons-16x16.svg#globe";
       var urlDescription = url && url.description || "";
       var location = url && url.location || "";
 
       var cx = classNames;
       var availableContext = this.state.availableContext;
       return (
         React.createElement("div", {className: "room-context"}, 
           React.createElement("p", {className: cx({ "error": !!this.props.error,
--- a/browser/extensions/loop/content/panels/js/roomViews.jsx
+++ b/browser/extensions/loop/content/panels/js/roomViews.jsx
@@ -341,24 +341,24 @@ loop.roomViews = (function(mozL10n) {
             hide: this.props.showEditContext
           })}>
             <div className={cx({
                 "btn-copy": true,
                 "invite-button": true,
                 "triggered": this.state.copiedUrl
               })}
               onClick={this.handleCopyButtonClick}>
-              <img src="loop/shared/img/svg/glyph-link-16x16.svg" />
+              <img src="shared/img/glyph-link-16x16.svg" />
               <p>{mozL10n.get(this.state.copiedUrl ?
                 "invite_copied_link_button" : "invite_copy_link_button")}</p>
             </div>
             <div className="btn-email invite-button"
               onClick={this.handleEmailButtonClick}
               onMouseOver={this.resetTriggeredButtons}>
-              <img src="loop/shared/img/svg/glyph-email-16x16.svg" />
+              <img src="shared/img/glyph-email-16x16.svg" />
               <p>{mozL10n.get("invite_email_link_button")}</p>
             </div>
           </div>
           <SocialShareDropdown
             dispatcher={this.props.dispatcher}
             ref="menu"
             roomUrl={this.props.roomData.roomUrl}
             show={this.state.showMenu}
@@ -531,17 +531,17 @@ loop.roomViews = (function(mozL10n) {
     },
 
     render: function() {
       if (!this.state.show) {
         return null;
       }
 
       var url = this._getURL();
-      var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
+      var thumbnail = url && url.thumbnail || "shared/img/icons-16x16.svg#globe";
       var urlDescription = url && url.description || "";
       var location = url && url.location || "";
 
       var cx = classNames;
       var availableContext = this.state.availableContext;
       return (
         <div className="room-context">
           <p className={cx({ "error": !!this.props.error,
--- a/browser/extensions/loop/content/panels/panel.html
+++ b/browser/extensions/loop/content/panels/panel.html
@@ -1,35 +1,36 @@
 <!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">
-    <link rel="stylesheet" type="text/css" href="loop/shared/css/reset.css">
-    <link rel="stylesheet" type="text/css" href="loop/shared/css/common.css">
-    <link rel="stylesheet" type="text/css" href="loop/css/panel.css">
+    <base href="chrome://loop/content">
+    <link rel="stylesheet" type="text/css" href="shared/css/reset.css">
+    <link rel="stylesheet" type="text/css" href="shared/css/common.css">
+    <link rel="stylesheet" type="text/css" href="panels/css/panel.css">
   </head>
   <body class="panel">
 
     <div id="main"></div>
 
-    <script type="text/javascript" src="loop/shared/libs/react-0.13.3.js"></script>
-    <script type="text/javascript" src="loop/libs/l10n.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/lodash-3.9.3.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/backbone-1.2.1.js"></script>
-    <script type="text/javascript" src="loop/shared/libs/classnames-2.2.0.js"></script>
+    <script type="text/javascript" src="panels/vendor/l10n.js"></script>
+    <script type="text/javascript" src="shared/vendor/react-0.13.3.js"></script>
+    <script type="text/javascript" src="shared/vendor/lodash-3.9.3.js"></script>
+    <script type="text/javascript" src="shared/vendor/backbone-1.2.1.js"></script>
+    <script type="text/javascript" src="shared/vendor/classnames-2.2.0.js"></script>
 
-    <script type="text/javascript" src="loop/shared/js/loopapi-client.js"></script>
-    <script type="text/javascript" src="loop/shared/js/utils.js"></script>
-    <script type="text/javascript" src="loop/shared/js/models.js"></script>
-    <script type="text/javascript" src="loop/shared/js/mixins.js"></script>
-    <script type="text/javascript" src="loop/shared/js/views.js"></script>
-    <script type="text/javascript" src="loop/shared/js/validate.js"></script>
-    <script type="text/javascript" src="loop/shared/js/actions.js"></script>
-    <script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
-    <script type="text/javascript" src="loop/shared/js/store.js"></script>
-    <script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
-    <script type="text/javascript" src="loop/js/roomStore.js"></script>
-    <script type="text/javascript" src="loop/js/panel.js"></script>
+    <script type="text/javascript" src="shared/js/loopapi-client.js"></script>
+    <script type="text/javascript" src="shared/js/utils.js"></script>
+    <script type="text/javascript" src="shared/js/models.js"></script>
+    <script type="text/javascript" src="shared/js/mixins.js"></script>
+    <script type="text/javascript" src="shared/js/views.js"></script>
+    <script type="text/javascript" src="shared/js/validate.js"></script>
+    <script type="text/javascript" src="shared/js/actions.js"></script>
+    <script type="text/javascript" src="shared/js/dispatcher.js"></script>
+    <script type="text/javascript" src="shared/js/store.js"></script>
+    <script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
+    <script type="text/javascript" src="panels/js/roomStore.js"></script>
+    <script type="text/javascript" src="panels/js/panel.js"></script>
  </body>
 </html>
--- a/browser/extensions/loop/content/shared/css/conversation.css
+++ b/browser/extensions/loop/content/shared/css/conversation.css
@@ -60,127 +60,127 @@ html[dir="rtl"] .conversation-toolbar > 
      extra gap which appears to push the toolbar in further than necessary */
   width: 28px;
 }
 
 .conversation-toolbar-media-btn-group-box {
   background-position: center;
   background-repeat: no-repeat;
   background-color: transparent;
-  background-image: url("../img/svg/media-group.svg");
+  background-image: url("../img/media-group.svg");
   background-size: cover;
   height: 28px;
   width: 67px;
 }
 
 .conversation-toolbar-media-btn-group-box > button:last-child:active,
 .conversation-toolbar-media-btn-group-box > button:last-child:hover {
-  background-image: url("../img/svg/media-group-right-hover.svg");
+  background-image: url("../img/media-group-right-hover.svg");
   background-size: cover;
 }
 
 html[dir="rtl"] .conversation-toolbar-media-btn-group-box > button:last-child:active,
 html[dir="rtl"] .conversation-toolbar-media-btn-group-box > button:last-child:hover {
-  background-image: url("../img/svg/media-group-left-hover.svg");
+  background-image: url("../img/media-group-left-hover.svg");
   background-size: cover;
 }
 
 .conversation-toolbar-media-btn-group-box > button:first-child:active,
 .conversation-toolbar-media-btn-group-box > button:first-child:hover {
-  background-image: url("../img/svg/media-group-left-hover.svg");
+  background-image: url("../img/media-group-left-hover.svg");
   background-size: cover;
 }
 
 html[dir="rtl"] .conversation-toolbar-media-btn-group-box > button:first-child:active,
 html[dir="rtl"] .conversation-toolbar-media-btn-group-box > button:first-child:hover {
-  background-image: url("../img/svg/media-group-right-hover.svg");
+  background-image: url("../img/media-group-right-hover.svg");
   background-size: cover;
 }
 
 .conversation-toolbar-btn-box.btn-edit-entry {
   float: right;
 }
 
 html[dir="rtl"] .conversation-toolbar-btn-box.btn-edit-entry {
   float: left;
 }
 
 /* conversationViews.jsx */
 
 .conversation-toolbar .btn-hangup {
-  background-image: url("../img/svg/exit.svg");
+  background-image: url("../img/exit.svg");
   border: 0;
 }
 
 /* Audio mute button */
 .btn-mute-audio:after {
-  content: url("../img/svg/audio.svg");
+  content: url("../img/audio.svg");
 }
 
 .btn-mute-audio.muted:after {
-  content: url("../img/svg/audio-mute.svg");
+  content: url("../img/audio-mute.svg");
 }
 .btn-mute-audio:hover:after,
 .btn-mute-audio:active:after {
-  content: url("../img/svg/audio-hover.svg");
+  content: url("../img/audio-hover.svg");
 }
 
 .btn-mute-audio.muted:hover:after,
 .btn-mute-audio.muted:active:after {
-  content: url("../img/svg/audio-mute-hover.svg");
+  content: url("../img/audio-mute-hover.svg");
 }
 
 /* Video mute button */
 .btn-mute-video:after {
-  content: url("../img/svg/video.svg");
+  content: url("../img/video.svg");
 }
 
 .btn-mute-video:active:after,
 .btn-mute-video:hover:after {
-  content: url("../img/svg/video-hover.svg");
+  content: url("../img/video-hover.svg");
 }
 
 .btn-mute-video.muted:after {
-  content: url("../img/svg/video-mute.svg");
+  content: url("../img/video-mute.svg");
 }
 
 .btn-mute-video.muted:hover:after,
 .btn-mute-video.muted:active:after {
-  content: url("../img/svg/video-mute-hover.svg");
+  content: url("../img/video-mute-hover.svg");
 }
 
 .btn-settings {
   width: 28px;
   height: 28px;
   background-size: 28px;
-  background-image: url("../img/svg/settings.svg");
+  background-image: url("../img/settings.svg");
   background-color: transparent;
 }
 
 .btn-settings:hover,
 .btn-settings:active {
-  background-image: url("../img/svg/settings-hover.svg");
+  background-image: url("../img/settings-hover.svg");
 }
 
 .btn-screen-share {
-  background-image: url("../img/svg/sharing.svg");
+  background-image: url("../img/sharing.svg");
 }
 
 .btn-screen-share:hover,
 .btn-screen-share:active {
-  background-image: url("../img/svg/sharing-hover.svg");
+  background-image: url("../img/sharing-hover.svg");
 }
 
 .btn-screen-share.active {
-  background-image: url("../img/svg/sharing-active.svg");
+  background-image: url("../img/sharing-active.svg");
 }
 
 .btn-screen-share.disabled {
   /* The screen share button is in its pending state when its disabled. */
-  background-image: url("../img/svg/sharing-pending.svg");
+  background-image: url("../img/sharing-pending.svg");
 }
 
 /* General Call (incoming or outgoing). */
 
 .call-action-group {
   display: flex;
   padding: 0 4px;
   width: 100%;
--- a/browser/extensions/loop/content/shared/js/crypto.js
+++ b/browser/extensions/loop/content/shared/js/crypto.js
@@ -13,17 +13,17 @@ var inChrome = typeof Components != "und
   var sharedUtils;
   if (inChrome) {
     this.EXPORTED_SYMBOLS = ["LoopCrypto"];
     var Cu = Components.utils;
     Cu.importGlobalProperties(["crypto"]);
     rootObject = {
       crypto: crypto
     };
-    sharedUtils = Cu.import("resource:///modules/loop/utils.js", {}).utils;
+    sharedUtils = Cu.import("chrome://loop/content/shared/js/utils.js", {}).utils;
   } else {
     sharedUtils = this.shared.utils;
   }
 
   var ALGORITHM = "AES-GCM";
   var KEY_LENGTH = 128;
   // We use JSON web key formats for the generated keys.
   // https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
--- a/browser/extensions/loop/content/shared/js/views.js
+++ b/browser/extensions/loop/content/shared/js/views.js
@@ -849,17 +849,17 @@ loop.shared.views = (function(_, mozL10n
       } catch (ex) {
         return null;
       }
 
       var thumbnail = this.props.thumbnail;
 
       if (!thumbnail) {
         thumbnail = this.props.useDesktopPaths ?
-          "loop/shared/img/icons-16x16.svg#globe" :
+          "shared/img/icons-16x16.svg#globe" :
           "shared/img/icons-16x16.svg#globe";
       }
 
       var wrapperClasses = classNames({
         "context-wrapper": true,
         "clicks-allowed": this.props.allowClick
       });
 
--- a/browser/extensions/loop/content/shared/js/views.jsx
+++ b/browser/extensions/loop/content/shared/js/views.jsx
@@ -849,17 +849,17 @@ loop.shared.views = (function(_, mozL10n
       } catch (ex) {
         return null;
       }
 
       var thumbnail = this.props.thumbnail;
 
       if (!thumbnail) {
         thumbnail = this.props.useDesktopPaths ?
-          "loop/shared/img/icons-16x16.svg#globe" :
+          "shared/img/icons-16x16.svg#globe" :
           "shared/img/icons-16x16.svg#globe";
       }
 
       var wrapperClasses = classNames({
         "context-wrapper": true,
         "clicks-allowed": this.props.allowClick
       });
 
--- a/browser/extensions/loop/moz.build
+++ b/browser/extensions/loop/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-FINAL_TARGET = 'dist/bin/browser/features/loop@test.mozilla.org'
+FINAL_TARGET = 'dist/bin/browser/features/loop@mozilla.org'
 
 FINAL_TARGET_FILES += [
  'bootstrap.js'
 ]
 
 DIST_FILES += [
   'install.rdf.in'
 ]
--- a/browser/extensions/loop/skin/shared/loop.css
+++ b/browser/extensions/loop/skin/shared/loop.css
@@ -12,22 +12,22 @@
    */
   :-moz-any(toolbar, .widget-overflow-list) #loop-button > .toolbarbutton-icon,
   :-moz-any(toolbar, .widget-overflow-list) #loop-button > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
     max-width: 18px;
     margin: 0;
   }
 
   #loop-button {
-    list-style-image: url(chrome://browser/skin/loop/toolbar.png);
+    list-style-image: url(chrome://loop/skin/toolbar.png);
     -moz-image-region: rect(0, 18px, 18px, 0);
   }
 
   toolbar[brighttext] #loop-button {
-    list-style-image: url(chrome://browser/skin/loop/toolbar-inverted.png);
+    list-style-image: url(chrome://loop/skin/toolbar-inverted.png);
   }
 
   #loop-button[state="disabled"],
   #loop-button[disabled="true"] {
     -moz-image-region: rect(0, 36px, 18px, 18px);
   }
 
   #loop-button:not([disabled="true"])[state="error"] {
@@ -47,22 +47,22 @@
   }
 
   #loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
     -moz-image-region: rect(0, 126px, 18px, 108px);
   }
 
   @media (min-resolution: 1.1dppx) {
     #loop-button {
-      list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
+      list-style-image: url("chrome://loop/skin/toolbar@2x.png");
       -moz-image-region: rect(0, 36px, 36px, 0);
     }
 
     toolbar[brighttext] #loop-button {
-      list-style-image: url("chrome://browser/skin/loop/toolbar-inverted@2x.png");
+      list-style-image: url("chrome://loop/skin/toolbar-inverted@2x.png");
     }
 
     #loop-button[state="disabled"],
     #loop-button[disabled="true"] {
       -moz-image-region: rect(0, 72px, 36px, 36px);
     }
 
     #loop-button:not([disabled="true"])[state="error"] {
@@ -82,17 +82,17 @@
     }
 
     #loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
       -moz-image-region: rect(0, 252px, 36px, 216px);
     }
 
     #loop-button[cui-areatype="menu-panel"],
     toolbarpaletteitem[place="palette"] > #loop-button {
-      list-style-image: url(chrome://browser/skin/loop/menuPanel@2x.png);
+      list-style-image: url(chrome://loop/skin/menuPanel@2x.png);
       -moz-image-region: rect(0, 64px, 64px, 0);
     }
 
     /* Make sure that the state icons are not shown in the customization palette. */
     toolbarpaletteitem[place="palette"] > #loop-button {
       -moz-image-region: rect(0, 64px, 64px, 0) !important;
     }
 
@@ -120,17 +120,17 @@
     #loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
       -moz-image-region: rect(0, 448px, 64px, 384px);
     }
   }
 
   @media not all and (min-resolution: 1.1dppx) {
     #loop-button[cui-areatype="menu-panel"],
     toolbarpaletteitem[place="palette"] > #loop-button {
-      list-style-image: url(chrome://browser/skin/loop/menuPanel.png);
+      list-style-image: url(chrome://loop/skin/menuPanel.png);
       -moz-image-region: rect(0, 32px, 32px, 0);
     }
 
     /* Make sure that the state icons are not shown in the customization palette. */
     toolbarpaletteitem[place="palette"] > #loop-button {
       -moz-image-region: rect(0, 32px, 32px, 0) !important;
     }
 
--- a/browser/extensions/loop/skin/windows/platform.css
+++ b/browser/extensions/loop/skin/windows/platform.css
@@ -1,18 +1,18 @@
 /* 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/. */
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 @media (-moz-windows-theme: luna-silver) and (max-resolution: 1dppx) {
   #loop-button {
-    list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
+    list-style-image: url(chrome://loop/skin/toolbar-lunaSilver.png)
   }
 }
 
 @media (-moz-windows-theme: luna-silver) and (min-resolution: 1.1dppx) {
   #loop-button {
-    list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver@2x.png)
+    list-style-image: url(chrome://loop/skin/toolbar-lunaSilver@2x.png)
   }
 }
 
--- a/browser/extensions/loop/standalone/content/css/webapp.css
+++ b/browser/extensions/loop/standalone/content/css/webapp.css
@@ -82,17 +82,17 @@ html[dir="rtl"] .standalone-overlay-wrap
   left: 0;
   right: auto;
 }
 
 .standalone-overlay-wrapper .icon-help {
   background-size: contain;
   width: 16px;
   height: 16px;
-  background: transparent url("../shared/img/svg/glyph-help-16x16.svg") no-repeat;
+  background: transparent url("../shared/img/glyph-help-16x16.svg") no-repeat;
 }
 
 .standalone-overlay-wrapper > .standalone-moz-logo {
   width: 50px;
   height: 13px;
   position: absolute;
   bottom: 0;
   right: 0;
@@ -266,17 +266,17 @@ html[dir="rtl"] .standalone-overlay-wrap
   justify-content: space-between;
   margin: 3em auto 1em;
   /* This should match the width set in the room-waiting-tile to ensure the edges
      of the content aligns within the tile width. */
   width: 290px;
 }
 
 .room-inner-info-area > .room-waiting-area > a >.room-waiting-help {
-  background: transparent url("../shared/img/svg/glyph-help-16x16.svg") no-repeat;
+  background: transparent url("../shared/img/glyph-help-16x16.svg") no-repeat;
   display: inline-block;
   height: 16px;
   margin-left: 5px;
   vertical-align: middle;
   width: 16px;
 }
 
 .room-inner-info-area > .room-waiting-tile {
--- a/browser/extensions/loop/standalone/content/webappEntryPoint.js
+++ b/browser/extensions/loop/standalone/content/webappEntryPoint.js
@@ -12,42 +12,42 @@
 // To get started, we're using webpack's script loader to load these things in
 // as-is.
 
 /* global require */
 
 // The OpenTok SDK tries to do some heuristic detection of require and
 // assumes a node environment if it's present, which confuses webpack, so
 // we turn that off by forcing require to false in that context.
-require("imports?require=>false!shared/libs/sdk.js");
+require("imports?require=>false!shared/vendor/sdk.js");
 
 // Ultimately, we'll likely want to pull the vendor libraries from npm, as that
 // makes upgrading easier, and it's generally better practice to minify the
 // "source" versions of libraries rather than built artifacts.  We probably do
 // want to minify them ourselves since this allows for better dead-code
 // elimination, but that can be a bit of judgement call.
-require("exports?_!shared/libs/lodash-3.9.3.js");
+require("exports?_!shared/vendor/lodash-3.9.3.js");
 
 // Disable Backbone's AMD auto-detection, as described at:
 //
 // https://github.com/jashkenas/backbone/wiki/Using-Backbone-without-jQuery
 //
-require("expose?Backbone!imports?define=>false!shared/libs/backbone-1.2.1.js");
+require("expose?Backbone!imports?define=>false!shared/vendor/backbone-1.2.1.js");
 
 /* global: __PROD__ */
 if (typeof __PROD__ !== "undefined") {
   // webpack warns if we try to minify some prebuilt libraries, so we
   // pull in the unbuilt version from node_modules
   require("expose?React!react");
   require("expose?React!react/addons");
   require("expose?classNames!classnames");
 } else {
   // our development server setup doesn't yet handle real modules, so for now...
-  require("shared/libs/react-0.13.3.js");
-  require("shared/libs/classnames-2.2.0.js");
+  require("shared/vendor/react-0.13.3.js");
+  require("shared/vendor/classnames-2.2.0.js");
 }
 
 
 // Someday, these will be real modules.  For now, we're chaining loaders
 // to teach webpack how to treat them like modules anyway.
 //
 // We do it in this file rather than globally in webpack.config.js
 // because:
--- a/browser/extensions/loop/standalone/server.js
+++ b/browser/extensions/loop/standalone/server.js
@@ -85,16 +85,20 @@ app.use("/content", express.static(path.
 // These two are based on the above, but handle call urls, that have a /c/ in them.
 app.use("/content/c", express.static(path.join(__dirname,
   standaloneContentDir)));
 app.use("/content/c", express.static(path.join(__dirname, "..", "content")));
 
 // Two lines for the same reason as /content above.
 app.use("/test", express.static(path.join(__dirname, "test")));
 app.use("/test", express.static(path.join(__dirname, "..", "test")));
+// Hacks for desktop to stop errors being raised in the tests for content loading.
+app.use("/test/shared/shared", express.static(path.join(__dirname, "..", "content/shared")));
+app.use("/test/desktop-local/shared", express.static(path.join(__dirname, "..", "content/shared")));
+
 
 // As we don't have hashes on the urls, the best way to serve the index files
 // appears to be to be to closely filter the url and match appropriately.
 function serveIndex(req, res) {
   "use strict";
 
   return res.sendFile(path.join(__dirname, standaloneContentDir, "index.html"));
 }
--- a/browser/extensions/loop/test/desktop-local/README.md
+++ b/browser/extensions/loop/test/desktop-local/README.md
@@ -6,16 +6,16 @@ and the Chai Assertion Library's [BDD in
 [1]: http://visionmedia.github.io/mocha/
 [2]: http://chaijs.com/api/bdd/
 
 Aim your browser at the index.html in this directory on your localhost using
 a file: or HTTP URL to run the tests.  Alternately, from the top-level of your
 Gecko source directory, execute:
 
 ```
-./mach marionette-test browser/components/loop/test/manifest.ini
+./mach marionette-test browser/extensions/loop/test/manifest.ini
 ```
 
 Next steps:
 
 * run using JS http server so the property security context for DOM elements
 is used
 
--- a/browser/extensions/loop/test/desktop-local/index.html
+++ b/browser/extensions/loop/test/desktop-local/index.html
@@ -9,27 +9,27 @@
   <link rel="stylesheet" media="all" href="../shared/vendor/mocha-2.2.5.css">
 </head>
 <body>
   <div id="mocha">
     <p><a href="../">Index</a></p>
   </div>
   <div id="messages"></div>
   <div id="fixtures"></div>
-  <script src="../../content/shared/libs/lodash-3.9.3.js"></script>
+  <script src="../../content/shared/vendor/lodash-3.9.3.js"></script>
   <script src="../shared/loop_mocha_utils.js"></script>
   <script>
     LoopMochaUtils.trapErrors();
   </script>
 
   <!-- libs -->
-  <script src="../../content/libs/l10n.js"></script>
-  <script src="../../content/shared/libs/react-0.13.3.js"></script>
-  <script src="../../content/shared/libs/classnames-2.2.0.js"></script>
-  <script src="../../content/shared/libs/backbone-1.2.1.js"></script>
+  <script src="../../content/panels/vendor/l10n.js"></script>
+  <script src="../../content/shared/vendor/react-0.13.3.js"></script>
+  <script src="../../content/shared/vendor/classnames-2.2.0.js"></script>
+  <script src="../../content/shared/vendor/backbone-1.2.1.js"></script>
 
   <!-- test dependencies -->
   <script src="../shared/vendor/mocha-2.2.5.js"></script>
   <script src="../shared/vendor/chai-3.0.0.js"></script>
   <script src="../shared/vendor/sinon-1.16.1.js"></script>
   <script>
     /*global chai,mocha */
     chai.config.includeStack = true;
@@ -45,22 +45,22 @@
   <script src="../../content/shared/js/validate.js"></script>
   <script src="../../content/shared/js/dispatcher.js"></script>
   <script src="../../content/shared/js/otSdkDriver.js"></script>
   <script src="../../content/shared/js/store.js"></script>
   <script src="../../content/shared/js/activeRoomStore.js"></script>
   <script src="../../content/shared/js/views.js"></script>
   <script src="../../content/shared/js/textChatStore.js"></script>
   <script src="../../content/shared/js/textChatView.js"></script>
-  <script src="../../content/js/conversationAppStore.js"></script>
-  <script src="../../content/js/roomStore.js"></script>
-  <script src="../../content/js/roomViews.js"></script>
-  <script src="../../content/js/feedbackViews.js"></script>
-  <script src="../../content/js/conversation.js"></script>
-  <script src="../../content/js/panel.js"></script>
+  <script src="../../content/panels/js/conversationAppStore.js"></script>
+  <script src="../../content/panels/js/roomStore.js"></script>
+  <script src="../../content/panels/js/roomViews.js"></script>
+  <script src="../../content/panels/js/feedbackViews.js"></script>
+  <script src="../../content/panels/js/conversation.js"></script>
+  <script src="../../content/panels/js/panel.js"></script>
 
   <!-- Test scripts -->
   <script src="conversationAppStore_test.js"></script>
   <script src="conversation_test.js"></script>
   <script src="feedbackViews_test.js"></script>
   <script src="panel_test.js"></script>
   <script src="roomViews_test.js"></script>
   <script src="l10n_test.js"></script>
--- a/browser/extensions/loop/test/karma/karma.coverage.desktop.js
+++ b/browser/extensions/loop/test/karma/karma.coverage.desktop.js
@@ -5,52 +5,52 @@
 
 module.exports = function(config) {
   "use strict";
 
   var baseConfig = require("./karma.conf.base.js")(config);
 
   // List of files / patterns to load in the browser.
   baseConfig.files = baseConfig.files.concat([
-    "content/libs/l10n.js",
-    "content/shared/libs/react-0.13.3.js",
-    "content/shared/libs/classnames-2.2.0.js",
-    "content/shared/libs/lodash-3.9.3.js",
-    "content/shared/libs/backbone-1.2.1.js",
+    "content/panels/vendor/l10n.js",
+    "content/shared/vendor/react-0.13.3.js",
+    "content/shared/vendor/classnames-2.2.0.js",
+    "content/shared/vendor/lodash-3.9.3.js",
+    "content/shared/vendor/backbone-1.2.1.js",
     "test/shared/vendor/*.js",
     "test/shared/loop_mocha_utils.js",
     "test/karma/head.js", // Stub out DOM event listener due to races.
     "content/shared/js/loopapi-client.js",
     "content/shared/js/utils.js",
     "content/shared/js/models.js",
     "content/shared/js/mixins.js",
     "content/shared/js/actions.js",
     "content/shared/js/otSdkDriver.js",
     "content/shared/js/validate.js",
     "content/shared/js/dispatcher.js",
     "content/shared/js/store.js",
     "content/shared/js/activeRoomStore.js",
     "content/shared/js/views.js",
     "content/shared/js/textChatStore.js",
     "content/shared/js/textChatView.js",
-    "content/js/feedbackViews.js",
-    "content/js/conversationAppStore.js",
-    "content/js/roomStore.js",
-    "content/js/roomViews.js",
-    "content/js/conversation.js",
+    "content/panels/js/feedbackViews.js",
+    "content/panels/js/conversationAppStore.js",
+    "content/panels/js/roomStore.js",
+    "content/panels/js/roomViews.js",
+    "content/panels/js/conversation.js",
     "test/desktop-local/*.js"
   ]);
 
   // List of files to exclude.
   baseConfig.exclude = baseConfig.exclude.concat([
     "test/desktop-local/panel_test.js"
   ]);
 
   // Preprocess matching files before serving them to the browser.
   // Available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor .
   baseConfig.preprocessors = {
-    "content/js/*.js": ["coverage"]
+    "content/panels/js/*.js": ["coverage"]
   };
 
   baseConfig.coverageReporter.dir = "test/coverage/desktop";
 
   config.set(baseConfig);
 };
--- a/browser/extensions/loop/test/karma/karma.coverage.shared_standalone.js
+++ b/browser/extensions/loop/test/karma/karma.coverage.shared_standalone.js
@@ -6,21 +6,21 @@
 module.exports = function(config) {
   "use strict";
 
   var baseConfig = require("./karma.conf.base.js")(config);
 
   // List of files / patterns to load in the browser.
   baseConfig.files = baseConfig.files.concat([
     "standalone/content/libs/l10n-gaia-02ca67948fe8.js",
-    "content/shared/libs/lodash-3.9.3.js",
-    "content/shared/libs/backbone-1.2.1.js",
-    "content/shared/libs/react-0.13.3.js",
-    "content/shared/libs/classnames-2.2.0.js",
-    "content/shared/libs/sdk.js",
+    "content/shared/vendor/lodash-3.9.3.js",
+    "content/shared/vendor/backbone-1.2.1.js",
+    "content/shared/vendor/react-0.13.3.js",
+    "content/shared/vendor/classnames-2.2.0.js",
+    "content/shared/vendor/sdk.js",
     "test/shared/vendor/*.js",
     "test/shared/loop_mocha_utils.js",
     "test/karma/head.js", // Add test fixture container
     "content/shared/js/loopapi-client.js",
     "content/shared/js/utils.js",
     "content/shared/js/store.js",
     "content/shared/js/models.js",
     "content/shared/js/mixins.js",
--- a/browser/extensions/loop/test/mochitest/browser_LoopRooms_channel.js
+++ b/browser/extensions/loop/test/mochitest/browser_LoopRooms_channel.js
@@ -7,17 +7,17 @@
  * window.
  */
 "use strict";
 
 var { WebChannel } = Cu.import("resource://gre/modules/WebChannel.jsm", {});
 var { Chat } = Cu.import("resource:///modules/Chat.jsm", {});
 
 const TEST_URI =
-  "example.com/browser/browser/components/loop/test/mochitest/test_loopLinkClicker_channel.html";
+  "example.com/browser/browser/extensions/loop/test/mochitest/test_loopLinkClicker_channel.html";
 const TEST_URI_GOOD = Services.io.newURI("https://" + TEST_URI, null, null);
 const TEST_URI_BAD = Services.io.newURI("http://" + TEST_URI, null, null);
 
 const ROOM_TOKEN = "fake1234";
 const LINKCLICKER_URL_PREFNAME = "loop.linkClicker.url";
 
 var openChatOrig = Chat.open;
 
--- a/browser/extensions/loop/test/mochitest/browser_fxa_login.js
+++ b/browser/extensions/loop/test/mochitest/browser_fxa_login.js
@@ -3,17 +3,17 @@
 
 /**
  * Test FxA logins with Loop.
  */
 
 "use strict";
 
 const BASE_URL = Services.prefs.getCharPref("loop.server");
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 
 function* checkFxA401() {
   let err = MozLoopService.errors.get("login");
   is(err.code, 401, "Check error code");
   is(err.friendlyMessage, getLoopString("could_not_authenticate"),
      "Check friendlyMessage");
   is(err.friendlyDetails, getLoopString("password_changed_question"),
      "Check friendlyDetails");
--- a/browser/extensions/loop/test/mochitest/browser_loop_fxa_server.js
+++ b/browser/extensions/loop/test/mochitest/browser_loop_fxa_server.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Test the server mocking FxA integration endpoints on the Loop server.
  */
 
 "use strict";
 
-const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
+const BASE_URL = "http://mochi.test:8888/browser/browser/extensions/loop/test/mochitest/loop_fxa.sjs?";
 
 registerCleanupFunction(function* () {
   yield promiseDeletedOAuthParams(BASE_URL);
 });
 
 add_task(function* required_setup_params() {
   let params = {
     client_id: "my_client_id",
--- a/browser/extensions/loop/test/mochitest/browser_mozLoop_appVersionInfo.js
+++ b/browser/extensions/loop/test/mochitest/browser_mozLoop_appVersionInfo.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 
 add_task(function* test_mozLoop_appVersionInfo() {
   let appVersionInfo;
   gHandlers.GetAppVersionInfo({}, result => appVersionInfo = result);
 
   Assert.ok(appVersionInfo, "should have appVersionInfo");
 
--- a/browser/extensions/loop/test/mochitest/browser_mozLoop_context.js
+++ b/browser/extensions/loop/test/mochitest/browser_mozLoop_context.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * This file contains tests for various context-in-conversations helpers in
  * LoopUI and Loop API.
  */
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 
 function promiseGetMetadata() {
   return new Promise(resolve => gHandlers.GetSelectedTabMetadata({}, resolve));
 }
 
 add_task(function* test_mozLoop_getSelectedTabMetadata() {
   let metadata = yield promiseGetMetadata();
--- a/browser/extensions/loop/test/mochitest/browser_mozLoop_sharingListeners.js
+++ b/browser/extensions/loop/test/mochitest/browser_mozLoop_sharingListeners.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * This file contains tests for the window.LoopUI active tab trackers.
  */
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 
 var handlers = [
   { windowId: null }, { windowId: null }
 ];
 
 function promiseWindowId() {
   return new Promise(resolve => {
--- a/browser/extensions/loop/test/mochitest/browser_mozLoop_socialShare.js
+++ b/browser/extensions/loop/test/mochitest/browser_mozLoop_socialShare.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 Cu.import("resource://gre/modules/Promise.jsm");
 const { SocialService } = Cu.import("resource://gre/modules/SocialService.jsm", {});
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 
 var [, gHandlers] = LoopAPI.inspect();
 
 const kShareProvider = {
   name: "provider 1",
   origin: "https://example.com",
   iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
   shareURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html"
--- a/browser/extensions/loop/test/mochitest/browser_mozLoop_telemetry.js
+++ b/browser/extensions/loop/test/mochitest/browser_mozLoop_telemetry.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * This file contains tests for the mozLoop telemetry API.
  */
 
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 var gConstants;
 gHandlers.GetAllConstants({}, constants => gConstants = constants);
 
 /**
  * Enable local telemetry recording for the duration of the tests.
  */
 add_task(function* test_initialize() {
--- a/browser/extensions/loop/test/mochitest/browser_toolbarbutton.js
+++ b/browser/extensions/loop/test/mochitest/browser_toolbarbutton.js
@@ -3,17 +3,17 @@
 
 /**
  * Test the toolbar button states.
  */
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/Promise.jsm", this);
-const { LoopRoomsInternal } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
+const { LoopRoomsInternal } = Components.utils.import("chrome://loop/content/modules/LoopRooms.jsm", {});
 Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
 
 const fxASampleToken = {
   token_type: "bearer",
   access_token: "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
   scope: "profile"
 };
 
--- a/browser/extensions/loop/test/mochitest/head.js
+++ b/browser/extensions/loop/test/mochitest/head.js
@@ -3,18 +3,18 @@
 
 "use strict";
 
 const HAWK_TOKEN_LENGTH = 64;
 const {
   LOOP_SESSION_TYPE,
   MozLoopServiceInternal,
   MozLoopService
-} = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
-const { LoopRooms } = Cu.import("resource:///modules/loop/LoopRooms.jsm", {});
+} = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
+const { LoopRooms } = Cu.import("chrome://loop/content/modules/LoopRooms.jsm", {});
 
 // Cache this value only once, at the beginning of a
 // test run, so that it doesn't pick up the offline=true
 // if offline mode is requested multiple times in a test run.
 const WAS_OFFLINE = Services.io.offline;
 
 function promisePanelLoaded() {
   return new Promise((resolve, reject) => {
@@ -128,17 +128,17 @@ function promiseOAuthParamsSetup(baseURL
     xhr.setRequestHeader("X-Params", JSON.stringify(params));
     xhr.addEventListener("load", () => resolve(xhr));
     xhr.addEventListener("error", error => reject(error));
     xhr.send();
   });
 }
 
 function* resetFxA() {
-  let global = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+  let global = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
   global.gHawkClient = null;
   global.gFxAOAuthClientPromise = null;
   global.gFxAOAuthClient = null;
   MozLoopServiceInternal.fxAOAuthProfile = null;
   MozLoopServiceInternal.fxAOAuthTokenData = null;
   const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
   Services.prefs.clearUserPref(fxASessionPref);
   MozLoopService.errors.clear();
@@ -147,17 +147,17 @@ function* resetFxA() {
   yield notified;
 }
 
 function checkFxAOAuthTokenData(aValue) {
   is(MozLoopServiceInternal.fxAOAuthTokenData, aValue, "fxAOAuthTokenData should be " + aValue);
 }
 
 function checkLoggedOutState() {
-  let global = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
+  let global = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
   is(global.gFxAOAuthClientPromise, null, "gFxAOAuthClientPromise should be cleared");
   is(MozLoopService.userProfile, null, "fxAOAuthProfile should be cleared");
   is(global.gFxAOAuthClient, null, "gFxAOAuthClient should be cleared");
   checkFxAOAuthTokenData(null);
   const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
   is(Services.prefs.getPrefType(fxASessionPref), Services.prefs.PREF_INVALID,
      "FxA hawk session should be cleared anyways");
 }
--- a/browser/extensions/loop/test/shared/index.html
+++ b/browser/extensions/loop/test/shared/index.html
@@ -9,26 +9,26 @@
   <link rel="stylesheet" media="all" href="vendor/mocha-2.2.5.css">
 </head>
 <body>
   <div id="mocha">
     <p><a href="../">Index</a></p>
   </div>
   <div id="messages"></div>
   <div id="fixtures"></div>
-  <script src="../../content/shared/libs/lodash-3.9.3.js"></script>
+  <script src="../../content/shared/vendor/lodash-3.9.3.js"></script>
   <script src="../shared/loop_mocha_utils.js"></script>
   <script>
     LoopMochaUtils.trapErrors();
   </script>
 
   <!-- libs -->
-  <script src="../../content/shared/libs/react-0.13.3.js"></script>
-  <script src="../../content/shared/libs/classnames-2.2.0.js"></script>
-  <script src="../../content/shared/libs/backbone-1.2.1.js"></script>
+  <script src="../../content/shared/vendor/react-0.13.3.js"></script>
+  <script src="../../content/shared/vendor/classnames-2.2.0.js"></script>
+  <script src="../../content/shared/vendor/backbone-1.2.1.js"></script>
   <script src="../../standalone/content/libs/l10n-gaia-02ca67948fe8.js"></script>
 
   <!-- test dependencies -->
   <script src="vendor/mocha-2.2.5.js"></script>
   <script src="vendor/chai-3.0.0.js"></script>
   <script src="vendor/chai-as-promised-5.1.0.js"></script>
   <script src="vendor/sinon-1.16.1.js"></script>
   <script>
--- a/browser/extensions/loop/test/shared/views_test.js
+++ b/browser/extensions/loop/test/shared/views_test.js
@@ -835,17 +835,17 @@ describe("loop.shared.views", function()
 
     it("should use a default thumbnail for desktop if one is not supplied", function() {
       view = mountTestComponent({
         useDesktopPaths: true,
         url: "http://wonderful.invalid"
       });
 
       expect(view.getDOMNode().querySelector(".context-preview").getAttribute("src"))
-        .eql("loop/shared/img/icons-16x16.svg#globe");
+        .eql("shared/img/icons-16x16.svg#globe");
     });
 
     it("should not display a title if by default", function() {
       view = mountTestComponent({
         url: "http://wonderful.invalid"
       });
 
       expect(view.getDOMNode().querySelector(".context-content > p")).eql(null);
--- a/browser/extensions/loop/test/standalone/index.html
+++ b/browser/extensions/loop/test/standalone/index.html
@@ -9,26 +9,26 @@
   <link rel="stylesheet" media="all" href="../shared/vendor/mocha-2.2.5.css">
 </head>
 <body>
   <div id="mocha">
     <p><a href="../">Index</a></p>
  </div>
   <div id="messages"></div>
   <div id="fixtures"></div>
-  <script src="../../content/shared/libs/lodash-3.9.3.js"></script>
+  <script src="../../content/shared/vendor/lodash-3.9.3.js"></script>
   <script src="../shared/loop_mocha_utils.js"></script>
   <script>
     LoopMochaUtils.trapErrors();
   </script>
 
   <!-- libs -->
-  <script src="../../content/shared/libs/react-0.13.3.js"></script>
-  <script src="../../content/shared/libs/classnames-2.2.0.js"></script>
-  <script src="../../content/shared/libs/backbone-1.2.1.js"></script>
+  <script src="../../content/shared/vendor/react-0.13.3.js"></script>
+  <script src="../../content/shared/vendor/classnames-2.2.0.js"></script>
+  <script src="../../content/shared/vendor/backbone-1.2.1.js"></script>
   <script src="../../standalone/content/libs/l10n-gaia-02ca67948fe8.js"></script>
   <!-- test dependencies -->
   <script src="../shared/vendor/mocha-2.2.5.js"></script>
   <script src="../shared/vendor/chai-3.0.0.js"></script>
   <script src="../shared/vendor/sinon-1.16.1.js"></script>
   <script src="../shared/sdk_mock.js"></script>
   <script>
     chai.config.includeStack = true;
--- a/browser/extensions/loop/test/xpcshell/.eslintrc
+++ b/browser/extensions/loop/test/xpcshell/.eslintrc
@@ -12,25 +12,27 @@
     "do_check_eq": false,
     "do_get_profile": false,
     "do_print": false,
     "do_register_cleanup": false,
     "do_throw": false,
     "do_timeout": false,
     "run_next_test": false,
     // head.js items.
+    "FileUtils": false,
     "MockWebSocketChannel": false,
     "extend": true,
     "getLoopString": false,
     "kServerPushUrl": true,
     "kEndPointUrl": true,
     "loopCrypto": true,
     "loopServer": true,
     "mockPushHandler": true,
     "setupFakeFxAUserProfile": false,
     "setupFakeLoopServer": false,
-    "timerHandlers",
+    "timerHandlers": false,
+    "updateAppInfo": false,
     "waitForCondition": true,
     // Loop specific items
     "MozLoopServiceInternal": true,
     "LoopRoomsInternal": true,
   }
 }
--- a/browser/extensions/loop/test/xpcshell/head.js
+++ b/browser/extensions/loop/test/xpcshell/head.js
@@ -7,25 +7,25 @@ var { classes: Cc, interfaces: Ci, utils
 
 // Initialize this before the imports, as some of them need it.
 do_get_profile();
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Http.jsm");
 Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource:///modules/loop/MozLoopService.jsm");
+Cu.import("chrome://loop/content/modules/MozLoopService.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource:///modules/loop/LoopRooms.jsm");
+Cu.import("chrome://loop/content/modules/LoopRooms.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
-const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
-const { LoopRoomsInternal, timerHandlers } = Cu.import("resource:///modules/loop/LoopRooms.jsm", {});
+const { MozLoopServiceInternal } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
+const { LoopRoomsInternal, timerHandlers } = Cu.import("chrome://loop/content/modules/LoopRooms.jsm", {});
 
 XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
-                                  "resource:///modules/loop/MozLoopPushHandler.jsm");
+                                  "chrome://loop/content/modules/MozLoopPushHandler.jsm");
 
 const kMockWebSocketChannelName = "Mock WebSocket Channel";
 const kWebSocketChannelContractID = "@mozilla.org/network/protocol;1?name=wss";
 
 const kServerPushUrl = "ws://localhost";
 const kLoopServerUrl = "http://localhost:3465";
 const kEndPointUrl = "http://example.com/fake";
 const kUAID = "f47ac11b-58ca-4372-9567-0e02b2c3d479";
--- a/browser/extensions/loop/test/xpcshell/test_loopapi_doNotDisturb.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopapi_doNotDisturb.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 
 add_task(function* test_mozLoop_doNotDisturb() {
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("loop.do_not_disturb");
   });
 
   // Test doNotDisturb (getter)
--- a/browser/extensions/loop/test/xpcshell/test_loopapi_internal.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopapi_internal.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 const [LoopAPIInternal] = LoopAPI.inspect();
 
 add_test(function test_intialize() {
   let [, , pageListeners] = LoopAPI.inspect();
   Assert.equal(pageListeners, null, "Page listeners should not be initialized yet");
 
   LoopAPIInternal.initialize();
   let [, , pageListeners2] = LoopAPI.inspect();
--- a/browser/extensions/loop/test/xpcshell/test_loopapi_prefs.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopapi_prefs.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
+const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
 var [, gHandlers] = LoopAPI.inspect();
 
 add_task(function* test_mozLoop_charPref() {
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("loop.test");
   });
 
   // Test setLoopPref
--- a/browser/extensions/loop/test/xpcshell/test_looprooms.js
+++ b/browser/extensions/loop/test/xpcshell/test_looprooms.js
@@ -1,16 +1,16 @@
 /* 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";
 
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource:///modules/loop/LoopRooms.jsm");
+Cu.import("chrome://loop/content/modules/LoopRooms.jsm");
 Cu.import("resource:///modules/Chat.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 timerHandlers.startTimer = callback => callback();
 
 var openChatOrig = Chat.open;
 
 const kKey = "uGIs-kGbYt1hBBwjyW7MLQ";
--- a/browser/extensions/loop/test/xpcshell/test_looprooms_encryption_in_fxa.js
+++ b/browser/extensions/loop/test/xpcshell/test_looprooms_encryption_in_fxa.js
@@ -2,17 +2,17 @@
  * 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";
 
 timerHandlers.startTimer = callback => callback();
 
 Cu.import("resource://services-common/utils.js");
-const { LOOP_ROOMS_CACHE_FILENAME } = Cu.import("resource:///modules/loop/LoopRoomsCache.jsm", {});
+const { LOOP_ROOMS_CACHE_FILENAME } = Cu.import("chrome://loop/content/modules/LoopRoomsCache.jsm", {});
 
 const kContextEnabledPref = "loop.contextInConverations.enabled";
 
 const kFxAKey = "uGIs-kGbYt1hBBwjyW7MLQ";
 
 // Rooms details as responded by the server.
 const kRoomsResponses = new Map([
   ["_nxD4V4FflQ", {
--- a/browser/extensions/loop/test/xpcshell/test_looprooms_first_notification.js
+++ b/browser/extensions/loop/test/xpcshell/test_looprooms_first_notification.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource:///modules/loop/LoopRooms.jsm");
+Cu.import("chrome://loop/content/modules/LoopRooms.jsm");
 Cu.import("resource:///modules/Chat.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 const kGuestKey = "uGIs-kGbYt1hBBwjyW7MLQ";
 const kChannelGuest = MozLoopService.channelIDs.roomsGuest;
 
 const kRoomsResponses = new Map([
   ["_nxD4V4FflQ", {
--- a/browser/extensions/loop/test/xpcshell/test_looprooms_getall.js
+++ b/browser/extensions/loop/test/xpcshell/test_looprooms_getall.js
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource:///modules/loop/LoopRooms.jsm");
 Cu.import("resource:///modules/Chat.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 timerHandlers.startTimer = callback => callback();
 
 var openChatOrig = Chat.open;
 
 const kKey = "uGIs-kGbYt1hBBwjyW7MLQ";
--- a/browser/extensions/loop/test/xpcshell/test_looprooms_upgrade_to_encryption.js
+++ b/browser/extensions/loop/test/xpcshell/test_looprooms_upgrade_to_encryption.js
@@ -1,18 +1,18 @@
 /* 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";
 
 Cu.import("resource://services-common/utils.js");
 
-const loopCrypto = Cu.import("resource:///modules/loop/crypto.js", {}).LoopCrypto;
-const { LOOP_ROOMS_CACHE_FILENAME } = Cu.import("resource:///modules/loop/LoopRoomsCache.jsm", {});
+const loopCrypto = Cu.import("chrome://loop/content/shared/js/crypto.js", {}).LoopCrypto;
+const { LOOP_ROOMS_CACHE_FILENAME } = Cu.import("chrome://loop/content/modules/LoopRoomsCache.jsm", {});
 
 var gTimerArgs = [];
 
 timerHandlers.startTimer = function(callback, delay) {
   gTimerArgs.push({ callback, delay });
   return gTimerArgs.length;
 };
 
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_hawk_errors.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_hawk_errors.js
@@ -5,17 +5,17 @@
  * Unit tests for the error handling for hawkRequest via setError.
  *
  * hawkRequest calls setError itself for 401. Consumers need to report other
  * errors to setError themseleves.
  */
 
 "use strict";
 
-const { INVALID_AUTH_TOKEN } = Cu.import("resource:///modules/loop/MozLoopService.jsm");
+const { INVALID_AUTH_TOKEN } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm");
 
 /**
  * An HTTP request for /NNN responds with a request with a status of NNN.
  */
 function errorRequestHandler(request, response) {
   let responseCode = request.path.substring(1);
   response.setStatusLine(null, responseCode, "Error");
   if (responseCode == 401) {
--- a/browser/extensions/loop/ui/README.md
+++ b/browser/extensions/loop/ui/README.md
@@ -1,10 +1,10 @@
 Loop UI Components Showcase
 ===========================
 
 This app file showcases all Loop's view components.
 
 If you want to modify the app, launch the following command:
 
-    browser/components/loop/build-jsx --watch
+    browser/extensions/loop/build-jsx --watch
 
 And start editing the `ui-showcase.jsx` file.
--- a/browser/extensions/loop/ui/index.html
+++ b/browser/extensions/loop/ui/index.html
@@ -5,55 +5,55 @@
 <html id="outer-html">
   <head>
     <meta charset="utf-8">
     <title>Loop UI Components Showcase</title>
     <link rel="stylesheet" type="text/css" href="../content/shared/css/reset.css">
     <link rel="stylesheet" type="text/css" href="../content/shared/css/common.css">
     <link rel="stylesheet" type="text/css" href="../content/shared/css/conversation.css">
     <link class="fx-embedded-panel" rel="stylesheet" type="text/css"
-          href="../content/css/panel.css">
+          href="../content/panels/css/panel.css">
     <link class="standalone" rel="stylesheet" type="text/css"
           href="../content/css/webapp.css">
     <link rel="stylesheet" type="text/css" href="ui-showcase.css">
  </head>
   <body>
     <script>
       var uncaughtError;
       window.addEventListener("error", function(error) {
         uncaughtError = error;
       });
     </script>
 
     <div id="main"></div>
     <div id="results"></div>
-    <script src="../content/shared/libs/react-0.13.3.js"></script>
-    <script src="../content/shared/libs/classnames-2.2.0.js"></script>
-    <script src="../content/shared/libs/lodash-3.9.3.js"></script>
-    <script src="../content/shared/libs/backbone-1.2.1.js"></script>
+    <script src="../content/shared/vendor/react-0.13.3.js"></script>
+    <script src="../content/shared/vendor/classnames-2.2.0.js"></script>
+    <script src="../content/shared/vendor/lodash-3.9.3.js"></script>
+    <script src="../content/shared/vendor/backbone-1.2.1.js"></script>
     <script src="../test/shared/loop_mocha_utils.js"></script>
     <script src="../content/shared/js/loopapi-client.js"></script>
     <script src="fake-mozLoop.js"></script>
     <script src="fake-l10n.js"></script>
     <script src="../content/shared/js/actions.js"></script>
     <script src="../content/shared/js/utils.js"></script>
     <script src="../content/shared/js/models.js"></script>
     <script src="../content/shared/js/mixins.js"></script>
     <script src="../content/shared/js/validate.js"></script>
     <script src="../content/shared/js/dispatcher.js"></script>
     <script src="../content/shared/js/store.js"></script>
     <script src="../content/shared/js/activeRoomStore.js"></script>
     <script src="../content/shared/js/views.js"></script>
     <script src="../content/shared/js/textChatStore.js"></script>
-    <script src="../content/js/feedbackViews.js"></script>
+    <script src="../content/panels/js/feedbackViews.js"></script>
     <script src="../content/shared/js/textChatView.js"></script>
     <script src="../content/shared/js/urlRegExps.js"></script>
     <script src="../content/shared/js/linkifiedTextView.js"></script>
-    <script src="../content/js/roomStore.js"></script>
-    <script src="../content/js/roomViews.js"></script>
+    <script src="../content/panels/js/roomStore.js"></script>
+    <script src="../content/panels/js/roomViews.js"></script>
     <script src="../standalone/content/js/webapp.js"></script>
     <script src="../standalone/content/js/standaloneRoomViews.js"></script>
-    <script src="../content/js/panel.js"></script>
-    <script src="../content/js/conversation.js"></script>
+    <script src="../content/panels/js/panel.js"></script>
+    <script src="../content/panels/js/conversation.js"></script>
     <script src="react-frame-component.js"></script>
     <script src="ui-showcase.js"></script>
   </body>
 </html>