diff --git a/UI/AddSeries/RootFolders/RootFolderCollection.js b/UI/AddSeries/RootFolders/RootFolderCollection.js
index e7c0caa9e..d6d20c471 100644
--- a/UI/AddSeries/RootFolders/RootFolderCollection.js
+++ b/UI/AddSeries/RootFolders/RootFolderCollection.js
@@ -1,5 +1,5 @@
 "use strict";
-define(['app', 'AddSeries/RootFolders/RootFolderModel'], function () {
+define(['app', 'AddSeries/RootFolders/RootFolderModel','mixins/backbone.signalr.mixin'], function () {
 
     var rootFolderCollection = Backbone.Collection.extend({
         url  : NzbDrone.Constants.ApiRoot + '/rootfolder',
@@ -7,4 +7,4 @@ define(['app', 'AddSeries/RootFolders/RootFolderModel'], function () {
     });
 
     return new rootFolderCollection().BindSignalR();
-});
\ No newline at end of file
+});
diff --git a/UI/Calendar/CalendarView.js b/UI/Calendar/CalendarView.js
index 950b0b939..03b517965 100644
--- a/UI/Calendar/CalendarView.js
+++ b/UI/Calendar/CalendarView.js
@@ -1,6 +1,6 @@
 'use strict';
 
-define(['app', 'Calendar/Collection'], function () {
+define(['app', 'Calendar/Collection','fullcalendar'], function () {
     NzbDrone.Calendar.CalendarView = Backbone.Marionette.ItemView.extend({
         initialize                   : function () {
             this.collection = new NzbDrone.Calendar.Collection();
diff --git a/UI/Cells/EpisodeStatusCell.js b/UI/Cells/EpisodeStatusCell.js
index 4401eeb4c..fee91b83c 100644
--- a/UI/Cells/EpisodeStatusCell.js
+++ b/UI/Cells/EpisodeStatusCell.js
@@ -1,6 +1,6 @@
 "use strict";
 
-define(['app' ], function () {
+define(['app','backgrid' ], function () {
     NzbDrone.Cells.EpisodeStatusCell = Backgrid.Cell.extend({
 
         className: 'episode-status-cell',
diff --git a/UI/Cells/FileSizeCell.js b/UI/Cells/FileSizeCell.js
index b80ec579d..4ae55c65d 100644
--- a/UI/Cells/FileSizeCell.js
+++ b/UI/Cells/FileSizeCell.js
@@ -1,6 +1,6 @@
 "use strict";
 
-define(['app', 'Shared/FormatHelpers'], function () {
+define(['app', 'Shared/FormatHelpers','backgrid'], function () {
     NzbDrone.Cells.FileSizeCell = Backgrid.Cell.extend({
 
         className: "file-size-cell",
diff --git a/UI/Cells/IndexerCell.js b/UI/Cells/IndexerCell.js
index 485e32fd3..59b5d4ff3 100644
--- a/UI/Cells/IndexerCell.js
+++ b/UI/Cells/IndexerCell.js
@@ -1,5 +1,5 @@
 "use strict";
-define(['app'], function () {
+define(['app','backgrid'], function () {
     NzbDrone.Cells.IndexerCell = Backgrid.Cell.extend({
 
         class : 'indexer-cell',
diff --git a/UI/Cells/NzbDroneCell.js b/UI/Cells/NzbDroneCell.js
index 580ba0273..3bb5dfe79 100644
--- a/UI/Cells/NzbDroneCell.js
+++ b/UI/Cells/NzbDroneCell.js
@@ -1,6 +1,6 @@
 "use strict";
 
-define(['app'], function () {
+define(['app','backgrid'], function () {
     NzbDrone.Cells.NzbDroneCell = Backgrid.Cell.extend({
 
         _originalInit: Backgrid.Cell.prototype.initialize,
diff --git a/UI/History/Collection.js b/UI/History/Collection.js
index 5b2a9be88..d9fb1b740 100644
--- a/UI/History/Collection.js
+++ b/UI/History/Collection.js
@@ -1,6 +1,6 @@
 "use strict";
-define(['app', 'History/Model'], function () {
-    NzbDrone.History.Collection = Backbone.PageableCollection.extend({
+define(['app', 'History/Model', 'backbone.pageable'], function (App, HistoryModel, PageableCollection) {
+    NzbDrone.History.Collection = PageableCollection.extend({
         url       : NzbDrone.Constants.ApiRoot + '/history',
         model     : NzbDrone.History.Model,
 
@@ -34,4 +34,4 @@ define(['app', 'History/Model'], function () {
             return resp;
         }
     });
-});
\ No newline at end of file
+});
diff --git a/UI/History/Row.js b/UI/History/Row.js
index 76003b0f2..e6aae27c1 100644
--- a/UI/History/Row.js
+++ b/UI/History/Row.js
@@ -1,9 +1,14 @@
-NzbDrone.Missing.Row = Backgrid.Row.extend({
-    events: {
-        'click .x-search'  : 'search'
-    },
+"use strict";
+define(['app','backgrid'], function () {
+    NzbDrone.Missing.Row = Backgrid.Row.extend({
+        events: {
+            'click .x-search': 'search'
+        },
 
-    search: function () {
-        window.alert('Episode Search');
-    }
-});
\ No newline at end of file
+        search: function () {
+            window.alert('Episode Search');
+        }
+    });
+
+    return NzbDrone.Missing.Row;
+});
diff --git a/UI/Index.html b/UI/Index.html
index 9b736d495..548798ea5 100644
--- a/UI/Index.html
+++ b/UI/Index.html
@@ -78,35 +78,12 @@
 </body>
 <script src="/JsLibraries/jquery.js"></script>
 <script src="/JsLibraries/messenger.js"></script>
-<script src="/Instrumentation/StringFormat.js"></script>
-<script src="/Instrumentation/ErrorHandler.js"></script>
-<script src="/JsLibraries/jquery.signalR.js"></script>
-<script src="/JsLibraries/bootstrap.js"></script>
-<script src="/JsLibraries/bootstrap.slider.js"></script>
-<script src="/JsLibraries/underscore.js"></script>
 <script src="/JsLibraries/handlebars.runtime.js"></script>
-<script src="/JsLibraries/backbone.js"></script>
-<script src="/JsLibraries/backbone.modelbinder.js"></script>
-<script src="/JsLibraries/backbone.deep.model.js"></script>
-<script src="/JsLibraries/backbone.mutators.js"></script>
-<script src="/JsLibraries/backbone.mutators.deep.model.js"></script>
-<script src="/JsLibraries/backbone.marionette.js"></script>
-<script src="/JsLibraries/backbone.pageable.js"></script>
 <script src="/JsLibraries/lunr.js"></script>
 <!--<script src="/JsLibraries/backbone.backgrid.js"></script>
 <script src="/JsLibraries/backbone.backgrid.filter.js"></script>-->
-<script src="/JsLibraries/jquery.backstretch.js"></script>
 <script src="/JsLibraries/sugar.js"></script>
-<script src="/JsLibraries/fullcalendar.js"></script>
-
 <script src="/templates.js"></script>
-
-<script src="/Mixins/backbone.marionette.templates.js"></script>
-<script src="/Mixins/backbone.marionette.region.mixin.js"></script>
-<script src="/Mixins/backbone.ajax.js"></script>
-<script src="/Mixins/backbone.modelbinder.mixin.js"></script>
-<script src="/Mixins/backbone.signalr.mixin.js"></script>
-
 <script data-main="/app" src="/JsLibraries/require.js"></script>
 <script src="/Routing.js"></script>
 </html>
diff --git a/UI/JsLibraries/backbone.deep.model.js b/UI/JsLibraries/backbone.deep.model.js
index 5307ffcf3..cbea78c52 100644
--- a/UI/JsLibraries/backbone.deep.model.js
+++ b/UI/JsLibraries/backbone.deep.model.js
@@ -1,124 +1,3 @@
-/*jshint expr:true eqnull:true */
-/**
- *
- * Backbone.DeepModel v0.10.4
- *
- * Copyright (c) 2013 Charles Davison, Pow Media Ltd
- *
- * https://github.com/powmedia/backbone-deep-model
- * Licensed under the MIT License
- */
-
-/**
- * Underscore mixins for deep objects
- *
- * Based on https://gist.github.com/echong/3861963
- */
-(function() {
-  var arrays, basicObjects, deepClone, deepExtend, deepExtendCouple, isBasicObject,
-    __slice = [].slice;
-
-  deepClone = function(obj) {
-    var func, isArr;
-    if (!_.isObject(obj) || _.isFunction(obj)) {
-      return obj;
-    }
-    if (obj instanceof Backbone.Collection || obj instanceof Backbone.Model) {
-      return obj;
-    }
-    if (_.isDate(obj)) {
-      return new Date(obj.getTime());
-    }
-    if (_.isRegExp(obj)) {
-      return new RegExp(obj.source, obj.toString().replace(/.*\//, ""));
-    }
-    isArr = _.isArray(obj || _.isArguments(obj));
-    func = function(memo, value, key) {
-      if (isArr) {
-        memo.push(deepClone(value));
-      } else {
-        memo[key] = deepClone(value);
-      }
-      return memo;
-    };
-    return _.reduce(obj, func, isArr ? [] : {});
-  };
-
-  isBasicObject = function(object) {
-    if (object == null) return false;
-    return (object.prototype === {}.prototype || object.prototype === Object.prototype) && _.isObject(object) && !_.isArray(object) && !_.isFunction(object) && !_.isDate(object) && !_.isRegExp(object) && !_.isArguments(object);
-  };
-
-  basicObjects = function(object) {
-    return _.filter(_.keys(object), function(key) {
-      return isBasicObject(object[key]);
-    });
-  };
-
-  arrays = function(object) {
-    return _.filter(_.keys(object), function(key) {
-      return _.isArray(object[key]);
-    });
-  };
-
-  deepExtendCouple = function(destination, source, maxDepth) {
-    var combine, recurse, sharedArrayKey, sharedArrayKeys, sharedObjectKey, sharedObjectKeys, _i, _j, _len, _len1;
-    if (maxDepth == null) {
-      maxDepth = 20;
-    }
-    if (maxDepth <= 0) {
-      console.warn('_.deepExtend(): Maximum depth of recursion hit.');
-      return _.extend(destination, source);
-    }
-    sharedObjectKeys = _.intersection(basicObjects(destination), basicObjects(source));
-    recurse = function(key) {
-      return source[key] = deepExtendCouple(destination[key], source[key], maxDepth - 1);
-    };
-    for (_i = 0, _len = sharedObjectKeys.length; _i < _len; _i++) {
-      sharedObjectKey = sharedObjectKeys[_i];
-      recurse(sharedObjectKey);
-    }
-    sharedArrayKeys = _.intersection(arrays(destination), arrays(source));
-    combine = function(key) {
-      return source[key] = _.union(destination[key], source[key]);
-    };
-    for (_j = 0, _len1 = sharedArrayKeys.length; _j < _len1; _j++) {
-      sharedArrayKey = sharedArrayKeys[_j];
-      combine(sharedArrayKey);
-    }
-    return _.extend(destination, source);
-  };
-
-  deepExtend = function() {
-    var finalObj, maxDepth, objects, _i;
-    objects = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), maxDepth = arguments[_i++];
-    if (!_.isNumber(maxDepth)) {
-      objects.push(maxDepth);
-      maxDepth = 20;
-    }
-    if (objects.length <= 1) {
-      return objects[0];
-    }
-    if (maxDepth <= 0) {
-      return _.extend.apply(this, objects);
-    }
-    finalObj = objects.shift();
-    while (objects.length > 0) {
-      finalObj = deepExtendCouple(finalObj, deepClone(objects.shift()), maxDepth);
-    }
-    return finalObj;
-  };
-
-  _.mixin({
-    deepClone: deepClone,
-    isBasicObject: isBasicObject,
-    basicObjects: basicObjects,
-    arrays: arrays,
-    deepExtend: deepExtend
-  });
-
-}).call(this);
-
 /**
  * Main source
  */
@@ -132,7 +11,7 @@
         factory(_, Backbone);
     }
 }(function(_, Backbone) {
-    
+
     /**
      * Takes a nested object and returns a shallow object keyed with the path names
      * e.g. { "level1.level2": "value" }
@@ -184,7 +63,7 @@
             if (result == null && i < n - 1) {
                 result = {};
             }
-            
+
             if (typeof result === 'undefined') {
                 if (return_exists)
                 {
@@ -233,7 +112,7 @@
     }
 
     function deleteNested(obj, path) {
-      setNested(obj, path, null, { unset: true });
+        setNested(obj, path, null, { unset: true });
     }
 
     var DeepModel = Backbone.Model.extend({
@@ -260,7 +139,7 @@
 
         // Return a copy of the model's `attributes` object.
         toJSON: function(options) {
-          return _.deepClone(this.attributes);
+            return _.deepClone(this.attributes);
         },
 
         // Override get
@@ -274,17 +153,17 @@
         set: function(key, val, options) {
             var attr, attrs, unset, changes, silent, changing, prev, current;
             if (key == null) return this;
-            
+
             // Handle both `"key", value` and `{key: value}` -style arguments.
             if (typeof key === 'object') {
-              attrs = key;
-              options = val || {};
+                attrs = key;
+                options = val || {};
             } else {
-              (attrs = {})[key] = val;
+                (attrs = {})[key] = val;
             }
 
             options || (options = {});
-            
+
             // Run validation.
             if (!this._validate(attrs, options)) return false;
 
@@ -296,8 +175,8 @@
             this._changing  = true;
 
             if (!changing) {
-              this._previousAttributes = _.deepClone(this.attributes); //<custom>: Replaced _.clone with _.deepClone
-              this.changed = {};
+                this._previousAttributes = _.deepClone(this.attributes); //<custom>: Replaced _.clone with _.deepClone
+                this.changed = {};
             }
             current = this.attributes, prev = this._previousAttributes;
 
@@ -310,50 +189,64 @@
 
             // For each `set` attribute, update or delete the current value.
             for (attr in attrs) {
-              val = attrs[attr];
-
-              //<custom code>: Using getNested, setNested and deleteNested
-              if (!_.isEqual(getNested(current, attr), val)) changes.push(attr);
-              if (!_.isEqual(getNested(prev, attr), val)) {
-                setNested(this.changed, attr, val);
-              } else {
-                deleteNested(this.changed, attr);
-              }
-              unset ? deleteNested(current, attr) : setNested(current, attr, val);
-              //</custom code>
+                val = attrs[attr];
+
+                //<custom code>: Using getNested, setNested and deleteNested
+                if (!_.isEqual(getNested(current, attr), val)) changes.push(attr);
+                if (!_.isEqual(getNested(prev, attr), val)) {
+                    setNested(this.changed, attr, val);
+                } else {
+                    deleteNested(this.changed, attr);
+                }
+                unset ? deleteNested(current, attr) : setNested(current, attr, val);
+                //</custom code>
             }
 
             // Trigger all relevant attribute changes.
             if (!silent) {
-              if (changes.length) this._pending = true;
-
-              //<custom code>
-              var separator = DeepModel.keyPathSeparator;
-
-              for (var i = 0, l = changes.length; i < l; i++) {
-                var key = changes[i];
-
-                this.trigger('change:' + key, this, getNested(current, key), options);
+                if (changes.length) this._pending = true;
 
-                var fields = key.split(separator);
-
-                //Trigger change events for parent keys with wildcard (*) notation
-                for(var n = fields.length - 1; n > 0; n--) {
-                  var parentKey = _.first(fields, n).join(separator),
-                      wildcardKey = parentKey + separator + '*';
-
-                  this.trigger('change:' + wildcardKey, this, getNested(current, parentKey), options);
+                //<custom code>
+                var separator = DeepModel.keyPathSeparator;
+                var alreadyTriggered = {}; // * @restorer
+
+                for (var i = 0, l = changes.length; i < l; i++) {
+                    var key = changes[i];
+
+                    if (!alreadyTriggered.hasOwnProperty(key) || !alreadyTriggered[key]) { // * @restorer
+                        alreadyTriggered[key] = true; // * @restorer
+                        this.trigger('change:' + key, this, getNested(current, key), options);
+                    } // * @restorer
+
+                    var fields = key.split(separator);
+
+                    //Trigger change events for parent keys with wildcard (*) notation
+                    for(var n = fields.length - 1; n > 0; n--) {
+                        var parentKey = _.first(fields, n).join(separator),
+                            wildcardKey = parentKey + separator + '*';
+
+                        if (!alreadyTriggered.hasOwnProperty(wildcardKey) || !alreadyTriggered[wildcardKey]) { // * @restorer
+                            alreadyTriggered[wildcardKey] = true; // * @restorer
+                            this.trigger('change:' + wildcardKey, this, getNested(current, parentKey), options);
+                        } // * @restorer
+
+                        // + @restorer
+                        if (!alreadyTriggered.hasOwnProperty(parentKey) || !alreadyTriggered[parentKey]) {
+                            alreadyTriggered[parentKey] = true;
+                            this.trigger('change:' + parentKey, this, getNested(current, parentKey), options);
+                        }
+                        // - @restorer
+                    }
+                    //</custom code>
                 }
-                //</custom code>
-              }
             }
 
             if (changing) return this;
             if (!silent) {
-              while (this._pending) {
-                this._pending = false;
-                this.trigger('change', this, options);
-              }
+                while (this._pending) {
+                    this._pending = false;
+                    this.trigger('change', this, options);
+                }
             }
             this._pending = false;
             this._changing = false;
@@ -363,17 +256,17 @@
         // Clear all attributes on the model, firing `"change"` unless you choose
         // to silence it.
         clear: function(options) {
-          var attrs = {};
-          var shallowAttributes = objToPaths(this.attributes);
-          for (var key in shallowAttributes) attrs[key] = void 0;
-          return this.set(attrs, _.extend({}, options, {unset: true}));
+            var attrs = {};
+            var shallowAttributes = objToPaths(this.attributes);
+            for (var key in shallowAttributes) attrs[key] = void 0;
+            return this.set(attrs, _.extend({}, options, {unset: true}));
         },
 
         // Determine if the model has changed since the last `"change"` event.
         // If you specify an attribute name, determine if that attribute has changed.
         hasChanged: function(attr) {
-          if (attr == null) return !_.isEmpty(this.changed);
-          return getNested(this.changed, attr) !== undefined;
+            if (attr == null) return !_.isEmpty(this.changed);
+            return getNested(this.changed, attr) !== undefined;
         },
 
         // Return an object containing all the attributes that have changed, or
@@ -383,41 +276,41 @@
         // You can also pass an attributes object to diff against the model,
         // determining if there *would be* a change.
         changedAttributes: function(diff) {
-          //<custom code>: objToPaths
-          if (!diff) return this.hasChanged() ? objToPaths(this.changed) : false;
-          //</custom code>
-
-          var old = this._changing ? this._previousAttributes : this.attributes;
-          
-          //<custom code>
-          diff = objToPaths(diff);
-          old = objToPaths(old);
-          //</custom code>
-
-          var val, changed = false;
-          for (var attr in diff) {
-            if (_.isEqual(old[attr], (val = diff[attr]))) continue;
-            (changed || (changed = {}))[attr] = val;
-          }
-          return changed;
+            //<custom code>: objToPaths
+            if (!diff) return this.hasChanged() ? objToPaths(this.changed) : false;
+            //</custom code>
+
+            var old = this._changing ? this._previousAttributes : this.attributes;
+
+            //<custom code>
+            diff = objToPaths(diff);
+            old = objToPaths(old);
+            //</custom code>
+
+            var val, changed = false;
+            for (var attr in diff) {
+                if (_.isEqual(old[attr], (val = diff[attr]))) continue;
+                (changed || (changed = {}))[attr] = val;
+            }
+            return changed;
         },
 
         // Get the previous value of an attribute, recorded at the time the last
         // `"change"` event was fired.
         previous: function(attr) {
-          if (attr == null || !this._previousAttributes) return null;
+            if (attr == null || !this._previousAttributes) return null;
 
-          //<custom code>
-          return getNested(this._previousAttributes, attr);
-          //</custom code>
+            //<custom code>
+            return getNested(this._previousAttributes, attr);
+            //</custom code>
         },
 
         // Get all of the attributes of the model at the time of the previous
         // `"change"` event.
         previousAttributes: function() {
-          //<custom code>
-          return _.deepClone(this._previousAttributes);
-          //</custom code>
+            //<custom code>
+            return _.deepClone(this._previousAttributes);
+            //</custom code>
         }
     });
 
@@ -431,8 +324,7 @@
 
     //For use in NodeJS
     if (typeof module != 'undefined') module.exports = DeepModel;
-    
+
     return Backbone;
 
 }));
-
diff --git a/UI/JsLibraries/backbone.mutators.deep.model.js b/UI/JsLibraries/backbone.mutators.deep.model.js
deleted file mode 100644
index 8bbebc069..000000000
--- a/UI/JsLibraries/backbone.mutators.deep.model.js
+++ /dev/null
@@ -1,211 +0,0 @@
-/*! Backbone.Mutators - v0.4.0
-------------------------------
-Build @ 2013-05-01
-Documentation and Full License Available at:
-http://asciidisco.github.com/Backbone.Mutators/index.html
-git://github.com/asciidisco/Backbone.Mutators.git
-Copyright (c) 2013 Sebastian Golasch <public@asciidisco.com>
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-
-Software is furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-IN THE SOFTWARE.*/
-(function (root, factory, undef) {
-    'use strict';
-
-    if (typeof exports === 'object') {
-        // Node. Does not work with strict CommonJS, but
-        // only CommonJS-like enviroments that support module.exports,
-        // like Node.
-        module.exports = factory(require('underscore'), require('Backbone'));
-    } else if (typeof define === 'function' && define.amd) {
-        // AMD. Register as an anonymous module.
-        define(['underscore', 'backbone'], function (_, Backbone) {
-            // Check if we use the AMD branch of Back
-            _ = _ === undef ? root._ : _;
-            Backbone = Backbone === undef ? root.Backbone : Backbone;
-            return (root.returnExportsGlobal = factory(_, Backbone, root));
-        });
-    } else {
-        // Browser globals
-        root.returnExportsGlobal = factory(root._, root.Backbone);
-    }
-
-// Usage:
-//
-// Note: This plugin is UMD compatible, you can use it in node, amd and vanilla js envs
-//
-// Vanilla JS:
-// <script src="underscore.js"></script>
-// <script src="backbone.js"></script>
-// <script src="backbone.mutators.js"></script>
-//
-// Node:
-// var _ = require('underscore');
-// var Backbone = require('backbone');
-// var Mutators = require('backbone.mutators');
-//
-//
-// AMD:
-// define(['underscore', 'backbone', 'backbone.mutators'], function (_, Backbone, Mutators) {
-//    // insert sample from below
-//    return User;
-// });
-//
-// var User = Backbone.Model.extend({
-//    mutators: {
-//        fullname: function () {
-//            return this.firstname + ' ' + this.lastname;
-//        }
-//    },
-//
-//    defaults: {
-//        firstname: 'Sebastian',
-//        lastname: 'Golasch'
-//    }
-// });
-//
-// var user = new User();
-// user.get('fullname') // returns 'Sebastian Golasch'
-// user.toJSON() // return '{firstname: 'Sebastian', lastname: 'Golasch', fullname: 'Sebastian Golasch'}'
-
-}(this, function (_, Backbone, root, undef) {
-    'use strict';
-
-    // check if we use the amd branch of backbone and underscore
-    Backbone = Backbone === undef ? root.Backbone : Backbone;
-    _ = _ === undef ? root._ : _;
-
-    // extend backbones model prototype with the mutator functionality
-    var Mutator     = function () {},
-        oldGet      = Backbone.DeepModel.prototype.get,
-        oldSet      = Backbone.DeepModel.prototype.set,
-        oldToJson   = Backbone.DeepModel.prototype.toJSON;
-
-    // This is necessary to ensure that Models declared without the mutators object do not throw and error
-    Mutator.prototype.mutators = {};
-
-    // override get functionality to fetch the mutator props
-    Mutator.prototype.get = function (attr) {
-        var isMutator = this.mutators !== undef;
-
-        // check if we have a getter mutation
-        if (isMutator === true && _.isFunction(this.mutators[attr]) === true) {
-            return this.mutators[attr].call(this);
-        }
-
-        // check if we have a deeper nested getter mutation
-        if (isMutator === true && _.isObject(this.mutators[attr]) === true && _.isFunction(this.mutators[attr].get) === true) {
-            return this.mutators[attr].get.call(this);
-        }
-
-        return oldGet.call(this, attr);
-    };
-
-    // override set functionality to set the mutator props
-    Mutator.prototype.set = function (key, value, options) {
-        var isMutator = this.mutators !== undef,
-            ret = null,
-            attrs = null;
-
-        // seamleassly stolen from backbone core
-        // check if the setter action is triggered
-        // using key <-> value or object
-        if (_.isObject(key) || key === null) {
-            attrs = key;
-            options = value;
-        } else {
-            attrs = {};
-            attrs[key] = value;
-        }
-
-        // check if we have a deeper nested setter mutation
-        if (isMutator === true && _.isObject(this.mutators[key]) === true) {
-
-            // check if we need to set a single value
-            if (_.isFunction(this.mutators[key].set) === true) {
-                ret = this.mutators[key].set.call(this, key, attrs[key], options, _.bind(oldSet, this));
-            } else if(_.isFunction(this.mutators[key])){
-                ret = this.mutators[key].call(this, key, attrs[key], options, _.bind(oldSet, this));
-            }
-        }
-
-        if (_.isObject(attrs)) {
-            _.each(attrs, _.bind(function (attr, attrKey) {
-                var cur_ret = null;
-                if (isMutator === true && _.isObject(this.mutators[attrKey]) === true) {
-                    // check if we need to set a single value
-
-                    var meth = this.mutators[attrKey];
-                    if(_.isFunction(meth.set)){
-                        meth = meth.set;
-                    }
-
-                    if(_.isFunction(meth)){
-                        if (options === undef || (_.isObject(options) === true && options.silent !== true && (options.mutators !== undef && options.mutators.silent !== true))) {
-                            this.trigger('mutators:set:' + attrKey);
-                        }
-                        cur_ret = meth.call(this, attrKey, attr, options, _.bind(oldSet, this));
-                    }
-
-                }
-                if (cur_ret === null) {
-                    cur_ret = _.bind(oldSet, this)(attrKey, attr, options);
-                }
-
-                if (ret !== false) { ret = cur_ret; }
-
-            }, this));
-        }
-
-        //validation purposes
-        if (ret !== null) {
-            return ret;
-        }
-
-        return oldSet.call(this, key, value, options);
-    };
-
-    // override toJSON functionality to serialize mutator properties
-    Mutator.prototype.toJSON = function () {
-        // fetch ye olde values
-        var attr = oldToJson.call(this);
-        // iterate over all mutators (if there are some)
-        _.each(this.mutators, _.bind(function (mutator, name) {
-            // check if we have some getter mutations
-            if (_.isObject(this.mutators[name]) === true && _.isFunction(this.mutators[name].get)) {
-                attr[name] = _.bind(this.mutators[name].get, this)();
-            } else {
-                attr[name] = _.bind(this.mutators[name], this)();
-            }
-        }, this));
-
-        return attr;
-    };
-
-    // override get functionality to get HTML-escaped the mutator props
-    Mutator.prototype.escape = function (attr){
-        var val = this.get(attr);
-        return _.escape(val == null ? '' : '' + val);
-    };
-
-    // extend the models prototype
-    _.extend(Backbone.DeepModel.prototype, Mutator.prototype);
-
-    // make mutators globally available under the Backbone namespace
-    Backbone.Mutators = Mutator;
-    return Mutator;
-}));
diff --git a/UI/Logs/Collection.js b/UI/Logs/Collection.js
index b7d949f2c..cfc645874 100644
--- a/UI/Logs/Collection.js
+++ b/UI/Logs/Collection.js
@@ -1,24 +1,24 @@
 "use strict";
-define(['app', 'Logs/Model'], function () {
-    NzbDrone.Logs.Collection = Backbone.PageableCollection.extend({
-        url       : NzbDrone.Constants.ApiRoot + '/log',
-        model     : NzbDrone.Logs.Model,
+define(['app', 'Logs/Model', 'backbone.pageable'], function (app, SeriesModel, PagableCollection) {
+    NzbDrone.Logs.Collection = PagableCollection.extend({
+        url  : NzbDrone.Constants.ApiRoot + '/log',
+        model: NzbDrone.Logs.Model,
 
         state: {
             pageSize: 50,
-            sortKey: "time",
-            order: 1
+            sortKey : "time",
+            order   : 1
         },
 
         queryParams: {
-            totalPages: null,
+            totalPages  : null,
             totalRecords: null,
-            pageSize: 'pageSize',
-            sortKey: "sortKey",
-            order: "sortDir",
-            directions: {
+            pageSize    : 'pageSize',
+            sortKey     : "sortKey",
+            order       : "sortDir",
+            directions  : {
                 "-1": "asc",
-                "1": "desc"
+                "1" : "desc"
             }
         },
 
diff --git a/UI/Missing/Collection.js b/UI/Missing/Collection.js
index 812246373..4fc370aa6 100644
--- a/UI/Missing/Collection.js
+++ b/UI/Missing/Collection.js
@@ -1,24 +1,24 @@
 "use strict";
-define(['app', 'Series/EpisodeModel'], function () {
-    NzbDrone.Missing.Collection = Backbone.PageableCollection.extend({
-        url       : NzbDrone.Constants.ApiRoot + '/missing',
-        model     : NzbDrone.Series.EpisodeModel,
+define(['app', 'Series/EpisodeModel', 'backbone.pageable'], function (app, EpisodeModel, PagableCollection) {
+    NzbDrone.Missing.Collection = PagableCollection.extend({
+        url  : NzbDrone.Constants.ApiRoot + '/missing',
+        model: NzbDrone.Series.EpisodeModel,
 
         state: {
             pageSize: 15,
-            sortKey: "airDate",
-            order: 1
+            sortKey : "airDate",
+            order   : 1
         },
 
         queryParams: {
-            totalPages: null,
+            totalPages  : null,
             totalRecords: null,
-            pageSize: 'pageSize',
-            sortKey: "sortKey",
-            order: "sortDir",
-            directions: {
+            pageSize    : 'pageSize',
+            sortKey     : "sortKey",
+            order       : "sortDir",
+            directions  : {
                 "-1": "asc",
-                "1": "desc"
+                "1" : "desc"
             }
         },
 
@@ -34,4 +34,4 @@ define(['app', 'Series/EpisodeModel'], function () {
             return resp;
         }
     });
-});
\ No newline at end of file
+});
diff --git a/UI/Missing/Row.js b/UI/Missing/Row.js
index 76003b0f2..dc3d998b5 100644
--- a/UI/Missing/Row.js
+++ b/UI/Missing/Row.js
@@ -1,9 +1,16 @@
-NzbDrone.Missing.Row = Backgrid.Row.extend({
-    events: {
-        'click .x-search'  : 'search'
-    },
-
-    search: function () {
-        window.alert('Episode Search');
-    }
-});
\ No newline at end of file
+"use strict";
+define(['app','backgrid'], function () {
+
+    NzbDrone.Missing.Row = Backgrid.Row.extend({
+        events: {
+            'click .x-search': 'search'
+        },
+
+        search: function () {
+            window.alert('Episode Search');
+        }
+    });
+    return NzbDrone.Mixins.Row;
+
+});
+
diff --git a/UI/Mixins/SaveIfChangedModel.js b/UI/Mixins/SaveIfChangedModel.js
index af9012d1a..bebff25bd 100644
--- a/UI/Mixins/SaveIfChangedModel.js
+++ b/UI/Mixins/SaveIfChangedModel.js
@@ -1,8 +1,8 @@
 "use strict";
-(function () {
+define(['app'], function () {
 
     NzbDrone.Mixins.SaveIfChangedModel = {
-//        originalInitialize: this.initialize,
+        //        originalInitialize: this.initialize,
 
         initialize: function () {
             this.isSaved = true;
@@ -15,9 +15,9 @@
                 this.isSaved = true;
             }, this);
 
-//            if (originalInitialize) {
-//                originalInitialize.call(this);
-//            }
+            //            if (originalInitialize) {
+            //                originalInitialize.call(this);
+            //            }
         },
 
         saveIfChanged: function (options) {
@@ -26,4 +26,6 @@
             }
         }
     };
-}());
\ No newline at end of file
+
+    return NzbDrone.Missing.SaveIfChangedModel;
+});
diff --git a/UI/Mixins/backbone.ajax.js b/UI/Mixins/backbone.ajax.js
index cda69416f..139b4c0c4 100644
--- a/UI/Mixins/backbone.ajax.js
+++ b/UI/Mixins/backbone.ajax.js
@@ -1,6 +1,6 @@
 //try to add ajax data as query string to DELETE calls.
 "use strict";
-(function () {
+define(['jquery'], function () {
 
     var original = Backbone.ajax;
 
@@ -20,4 +20,4 @@
 
         return original.apply(this, arguments);
     };
-}());
+});
diff --git a/UI/Mixins/backbone.marionette.templates.js b/UI/Mixins/backbone.marionette.templates.js
index 542c257b2..d14fc8f47 100644
--- a/UI/Mixins/backbone.marionette.templates.js
+++ b/UI/Mixins/backbone.marionette.templates.js
@@ -1,24 +1,26 @@
 "use strict";
 
-Marionette.TemplateCache.get = function (templateId) {
+define(['app', 'marionette'], function (App, Marionette) {
+    Marionette.TemplateCache.get = function (templateId) {
 
-    var templateKey = templateId.toLowerCase();
+        var templateKey = templateId.toLowerCase();
 
-    var templateFunction = window.Templates[templateKey];
+        var templateFunction = window.Templates[templateKey];
 
-    if (!templateFunction) {
-        throw 'couldn\'t find pre-compiled template ' + templateKey;
-    }
+        if (!templateFunction) {
+            throw 'couldn\'t find pre-compiled template ' + templateKey;
+        }
 
-    return function (data) {
+        return function (data) {
 
-        try {
-            return templateFunction(data);
-        }
-        catch (error) {
-            console.error('template render failed for ' + templateKey + ' ' + error);
-            console.error(data);
-            throw error;
-        }
+            try {
+                return templateFunction(data);
+            }
+            catch (error) {
+                console.error('template render failed for ' + templateKey + ' ' + error);
+                console.error(data);
+                throw error;
+            }
+        };
     };
-};
+});
diff --git a/UI/Mixins/backbone.signalr.mixin.js b/UI/Mixins/backbone.signalr.mixin.js
index ef0c0bcde..313f39dbf 100644
--- a/UI/Mixins/backbone.signalr.mixin.js
+++ b/UI/Mixins/backbone.signalr.mixin.js
@@ -1,48 +1,49 @@
 "use strict";
+define(['app', 'signalR'], function () {
 
-_.extend(Backbone.Collection.prototype, {BindSignalR: function (options) {
+    _.extend(Backbone.Collection.prototype, {BindSignalR: function (options) {
 
-    if (!options || !options.url) {
-        console.assert(this.url, 'url must be provided or collection must have url');
-        options = {
-            url: this.url.replace('api', 'signalr')
-        };
-    }
-
-    var self = this;
-
-    var _getStatus = function (status) {
-        switch (status) {
-            case    0:
-                return 'connecting';
-            case 1:
-                return 'connected';
-            case 2:
-                return 'reconnecting';
-            case 4:
-                return 'disconnected';
-            default:
-                throw 'invalid status ' + status;
+        if (!options || !options.url) {
+            console.assert(this.url, 'url must be provided or collection must have url');
+            options = {
+                url: this.url.replace('api', 'signalr')
+            };
         }
 
-    };
+        var self = this;
+
+        var _getStatus = function (status) {
+            switch (status) {
+                case    0:
+                    return 'connecting';
+                case 1:
+                    return 'connected';
+                case 2:
+                    return 'reconnecting';
+                case 4:
+                    return 'disconnected';
+                default:
+                    throw 'invalid status ' + status;
+            }
 
+        };
 
-    var connection = $.connection(options.url);
 
-    connection.stateChanged(function (change) {
-        console.debug('{0} [{1}]'.format(options.url, _getStatus(change.newState)));
-    });
+        var connection = $.connection(options.url);
 
-    connection.received(function (model) {
-        console.debug(model);
-        self.fetch();
-    });
+        connection.stateChanged(function (change) {
+            console.debug('{0} [{1}]'.format(options.url, _getStatus(change.newState)));
+        });
 
-    connection.start({ transport: ['longPolling'] });
+        connection.received(function (model) {
+            console.debug(model);
+            self.fetch();
+        });
 
-    return this;
-}});
+        connection.start({ transport: ['longPolling'] });
 
+        return this;
+    }});
+});
 
 
diff --git a/UI/Mixins/underscore.mixin.deepExtend.js b/UI/Mixins/underscore.mixin.deepExtend.js
new file mode 100644
index 000000000..5b6a20f25
--- /dev/null
+++ b/UI/Mixins/underscore.mixin.deepExtend.js
@@ -0,0 +1,109 @@
+/**
+ * Underscore mixins for deep objects
+ *
+ * Based on https://gist.github.com/echong/3861963
+ */
+(function() {
+    var arrays, basicObjects, deepClone, deepExtend, deepExtendCouple, isBasicObject,
+        __slice = [].slice;
+
+    deepClone = function(obj) {
+        var func, isArr;
+        if (!_.isObject(obj) || _.isFunction(obj)) {
+            return obj;
+        }
+        if (obj instanceof Backbone.Collection || obj instanceof Backbone.Model) {
+            return obj;
+        }
+        if (_.isDate(obj)) {
+            return new Date(obj.getTime());
+        }
+        if (_.isRegExp(obj)) {
+            return new RegExp(obj.source, obj.toString().replace(/.*\//, ""));
+        }
+        isArr = _.isArray(obj || _.isArguments(obj));
+        func = function(memo, value, key) {
+            if (isArr) {
+                memo.push(deepClone(value));
+            } else {
+                memo[key] = deepClone(value);
+            }
+            return memo;
+        };
+        return _.reduce(obj, func, isArr ? [] : {});
+    };
+
+    isBasicObject = function(object) {
+        if (object == null) return false;
+        return (object.prototype === {}.prototype || object.prototype === Object.prototype) && _.isObject(object) && !_.isArray(object) && !_.isFunction(object) && !_.isDate(object) && !_.isRegExp(object) && !_.isArguments(object);
+    };
+
+    basicObjects = function(object) {
+        return _.filter(_.keys(object), function(key) {
+            return isBasicObject(object[key]);
+        });
+    };
+
+    arrays = function(object) {
+        return _.filter(_.keys(object), function(key) {
+            return _.isArray(object[key]);
+        });
+    };
+
+    deepExtendCouple = function(destination, source, maxDepth) {
+        var combine, recurse, sharedArrayKey, sharedArrayKeys, sharedObjectKey, sharedObjectKeys, _i, _j, _len, _len1;
+        if (maxDepth == null) {
+            maxDepth = 20;
+        }
+        if (maxDepth <= 0) {
+            console.warn('_.deepExtend(): Maximum depth of recursion hit.');
+            return _.extend(destination, source);
+        }
+        sharedObjectKeys = _.intersection(basicObjects(destination), basicObjects(source));
+        recurse = function(key) {
+            return source[key] = deepExtendCouple(destination[key], source[key], maxDepth - 1);
+        };
+        for (_i = 0, _len = sharedObjectKeys.length; _i < _len; _i++) {
+            sharedObjectKey = sharedObjectKeys[_i];
+            recurse(sharedObjectKey);
+        }
+        sharedArrayKeys = _.intersection(arrays(destination), arrays(source));
+        combine = function(key) {
+            return source[key] = _.union(destination[key], source[key]);
+        };
+        for (_j = 0, _len1 = sharedArrayKeys.length; _j < _len1; _j++) {
+            sharedArrayKey = sharedArrayKeys[_j];
+            combine(sharedArrayKey);
+        }
+        return _.extend(destination, source);
+    };
+
+    deepExtend = function() {
+        var finalObj, maxDepth, objects, _i;
+        objects = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), maxDepth = arguments[_i++];
+        if (!_.isNumber(maxDepth)) {
+            objects.push(maxDepth);
+            maxDepth = 20;
+        }
+        if (objects.length <= 1) {
+            return objects[0];
+        }
+        if (maxDepth <= 0) {
+            return _.extend.apply(this, objects);
+        }
+        finalObj = objects.shift();
+        while (objects.length > 0) {
+            finalObj = deepExtendCouple(finalObj, deepClone(objects.shift()), maxDepth);
+        }
+        return finalObj;
+    };
+
+    _.mixin({
+        deepClone: deepClone,
+        isBasicObject: isBasicObject,
+        basicObjects: basicObjects,
+        arrays: arrays,
+        deepExtend: deepExtend
+    });
+
+}).call(this);
diff --git a/UI/Quality/qualityProfileModel.js b/UI/Quality/qualityProfileModel.js
index 50cf01cf1..53662a9cf 100644
--- a/UI/Quality/qualityProfileModel.js
+++ b/UI/Quality/qualityProfileModel.js
@@ -1,6 +1,6 @@
 "use strict";
-define(['app'], function () {
-    NzbDrone.Quality.QualityProfileModel = Backbone.DeepModel.extend({
+define(['app', 'backbone.deepmodel'], function (App, DeepModel) {
+    NzbDrone.Quality.QualityProfileModel = DeepModel.DeepModel.extend({
 
         defaults: {
             id    : null,
diff --git a/UI/Release/Collection.js b/UI/Release/Collection.js
index ec094a0e8..a8333963a 100644
--- a/UI/Release/Collection.js
+++ b/UI/Release/Collection.js
@@ -1,6 +1,6 @@
 "use strict";
-define(['app', 'Release/Model'], function () {
-    NzbDrone.Release.Collection = Backbone.PageableCollection.extend({
+define(['app', 'Release/Model', 'backbone.pageable'], function (app, SeriesModel, PagableCollection) {
+    NzbDrone.Release.Collection = PagableCollection.extend({
         url  : NzbDrone.Constants.ApiRoot + '/release',
         model: NzbDrone.Release.Model,
 
diff --git a/UI/Release/DownloadReportCell.js b/UI/Release/DownloadReportCell.js
index da996bbb0..3bf832a14 100644
--- a/UI/Release/DownloadReportCell.js
+++ b/UI/Release/DownloadReportCell.js
@@ -1,27 +1,33 @@
 "use strict";
-NzbDrone.Release.DownloadReportCell = Backgrid.Cell.extend({
 
-    className: "download-report-cell",
+define(['app'], function () {
+    NzbDrone.Release.DownloadReportCell = Backgrid.Cell.extend({
 
-    events: {
-        'click': '_onClick'
-    },
+        className: "download-report-cell",
 
-    _onClick: function () {
+        events: {
+            'click': '_onClick'
+        },
 
-        var self = this;
+        _onClick: function () {
 
-        this.$el.html('<i class ="icon-spinner icon-spin" />');
-        this.model.save()
-            .always(function () {
-                self.$el.html('<i class ="icon-download-alt" />');
-            });
-    },
+            var self = this;
 
-    render: function () {
+            this.$el.html('<i class ="icon-spinner icon-spin" />');
+            this.model.save()
+                .always(function () {
+                    self.$el.html('<i class ="icon-download-alt" />');
+                });
+        },
 
-        this.$el.html('<i class ="icon-download-alt" />');
-        return this;
+        render: function () {
 
-    }
+            this.$el.html('<i class ="icon-download-alt" />');
+            return this;
+
+        }
+    });
+
+
+    return NzbDrone.Release.DownloadReportCell;
 });
diff --git a/UI/Series/Details/SeriesDetailsLayout.js b/UI/Series/Details/SeriesDetailsLayout.js
index f42745a04..4cb037fd4 100644
--- a/UI/Series/Details/SeriesDetailsLayout.js
+++ b/UI/Series/Details/SeriesDetailsLayout.js
@@ -1,5 +1,5 @@
 "use strict";
-define(['app', 'Series/Details/SeasonCollectionView', 'Shared/LoadingView'], function () {
+define(['app', 'Series/Details/SeasonCollectionView', 'Shared/LoadingView','backstrech'], function () {
         NzbDrone.Series.Details.SeriesDetailsLayout = Backbone.Marionette.Layout.extend({
 
             itemViewContainer: '.x-series-seasons',
diff --git a/UI/Series/Index/Table/Row.js b/UI/Series/Index/Table/Row.js
index 455e98a99..cd0b43c85 100644
--- a/UI/Series/Index/Table/Row.js
+++ b/UI/Series/Index/Table/Row.js
@@ -1,17 +1,22 @@
 "use strict";
-NzbDrone.Series.Index.Table.Row = Backgrid.Row.extend({
-    events: {
-        'click .x-edit'  : 'editSeries',
-        'click .x-remove': 'removeSeries'
-    },
+define(['app','backgrid'], function () {
+    NzbDrone.Series.Index.Table.Row = Backgrid.Row.extend({
+        events: {
+            'click .x-edit'  : 'editSeries',
+            'click .x-remove': 'removeSeries'
+        },
 
-    editSeries: function () {
-        var view = new NzbDrone.Series.Edit.EditSeriesView({ model: this.model});
-        NzbDrone.modalRegion.show(view);
-    },
+        editSeries: function () {
+            var view = new NzbDrone.Series.Edit.EditSeriesView({ model: this.model});
+            NzbDrone.modalRegion.show(view);
+        },
+
+        removeSeries: function () {
+            var view = new NzbDrone.Series.Delete.DeleteSeriesView({ model: this.model });
+            NzbDrone.modalRegion.show(view);
+        }
+    });
+
+    return NzbDrone.Series.Table.Row;
+});
 
-    removeSeries: function () {
-        var view = new NzbDrone.Series.Delete.DeleteSeriesView({ model: this.model });
-        NzbDrone.modalRegion.show(view);
-    }
-});
\ No newline at end of file
diff --git a/UI/Series/Index/Table/SeriesStatusCell.js b/UI/Series/Index/Table/SeriesStatusCell.js
index 1dd569d4c..b2a26ea8a 100644
--- a/UI/Series/Index/Table/SeriesStatusCell.js
+++ b/UI/Series/Index/Table/SeriesStatusCell.js
@@ -1,23 +1,27 @@
 "use strict";
-Backgrid.SeriesStatusCell = Backgrid.Cell.extend({
-    className: "series-status-cell",
+define(['app','backgrid'], function () {
+    Backgrid.SeriesStatusCell = Backgrid.Cell.extend({
+        className: "series-status-cell",
 
-    render: function () {
-        this.$el.empty();
-        var monitored = this.model.get('monitored');
-        var status = this.model.get('status');
+        render: function () {
+            this.$el.empty();
+            var monitored = this.model.get('monitored');
+            var status = this.model.get('status');
 
-        if (!monitored) {
-            this.$el.html('<i class="icon-pause grid-icon" title="Not Monitored"></i>');
-        }
-        else if (status === 'continuing') {
-            this.$el.html('<i class="icon-play grid-icon" title="Continuing"></i>');
-        }
+            if (!monitored) {
+                this.$el.html('<i class="icon-pause grid-icon" title="Not Monitored"></i>');
+            }
+            else if (status === 'continuing') {
+                this.$el.html('<i class="icon-play grid-icon" title="Continuing"></i>');
+            }
+
+            else {
+                this.$el.html('<i class="icon-stop grid-icon" title="Ended"></i>');
+            }
 
-        else {
-            this.$el.html('<i class="icon-stop grid-icon" title="Ended"></i>');
+            return this;
         }
+    });
 
-        return this;
-    }
+    return Backgrid.SeriesStatusCell;
 });
diff --git a/UI/Series/SeasonCollection.js b/UI/Series/SeasonCollection.js
index 8202f34f3..12dea609c 100644
--- a/UI/Series/SeasonCollection.js
+++ b/UI/Series/SeasonCollection.js
@@ -1,6 +1,6 @@
 "use strict";
-define(['app', 'Series/SeasonModel'], function () {
-    NzbDrone.Series.SeasonCollection = Backbone.PageableCollection.extend({
+define(['app', 'Series/SeasonModel', 'backbone.pageable'], function (App, SeasonModel, PageAbleCollection) {
+    NzbDrone.Series.SeasonCollection = PageAbleCollection.extend({
         url  : NzbDrone.Constants.ApiRoot + '/season',
         model: NzbDrone.Series.SeasonModel,
 
diff --git a/UI/Series/SeriesModel.js b/UI/Series/SeriesModel.js
index 9ba22f360..659be3eaf 100644
--- a/UI/Series/SeriesModel.js
+++ b/UI/Series/SeriesModel.js
@@ -66,7 +66,7 @@ define(['app', 'Quality/QualityProfileCollection'], function (app, qualityProfil
 
                 var profile = qualityProfiles.get(this.get('qualityProfileId'));
 
-                if(profile){
+                if (profile) {
                     return profile.toJSON();
                 }
 
@@ -82,4 +82,6 @@ define(['app', 'Quality/QualityProfileCollection'], function (app, qualityProfil
         }
     });
 
+    return NzbDrone.Series.SeriesModel;
+
 });
diff --git a/UI/Settings/DownloadClient/DownloadClientView.js b/UI/Settings/DownloadClient/DownloadClientView.js
index 4feec45bf..09bf825a6 100644
--- a/UI/Settings/DownloadClient/DownloadClientView.js
+++ b/UI/Settings/DownloadClient/DownloadClientView.js
@@ -1,7 +1,7 @@
 'use strict';
 
 define([
-    'app', 'Settings/SettingsModel'
+    'app', 'Settings/SettingsModel','bootstrap'
 
 ], function () {
 
diff --git a/UI/Settings/Indexers/Model.js b/UI/Settings/Indexers/Model.js
index acde63869..1d80214fa 100644
--- a/UI/Settings/Indexers/Model.js
+++ b/UI/Settings/Indexers/Model.js
@@ -1,7 +1,8 @@
 "use strict";
 define(['app',
-        'Mixins/SaveIfChangedModel'], function () {
-    NzbDrone.Settings.Indexers.Model = Backbone.DeepModel.extend({
+    'Mixins/SaveIfChangedModel',
+    'backbone.deepmodel'], function (App, SaveIfChangedModel, DeepModel) {
+    NzbDrone.Settings.Indexers.Model = DeepModel.DeepModel.extend({
     });
 
     _.extend(NzbDrone.Settings.Indexers.Model.prototype, NzbDrone.Mixins.SaveIfChangedModel);
diff --git a/UI/Settings/Notifications/Model.js b/UI/Settings/Notifications/Model.js
index bee0e1da4..0055d733e 100644
--- a/UI/Settings/Notifications/Model.js
+++ b/UI/Settings/Notifications/Model.js
@@ -1,5 +1,5 @@
 "use strict";
-define(['app'], function () {
-    NzbDrone.Settings.Notifications.Model = Backbone.DeepModel.extend({
+define(['app', 'backbone.deepmodel'], function (App, DeepModel) {
+    NzbDrone.Settings.Notifications.Model = DeepModel.DeepModel.extend({
     });
 });
diff --git a/UI/Settings/Quality/Size/QualitySizeView.js b/UI/Settings/Quality/Size/QualitySizeView.js
index ccce82543..084f8ce2a 100644
--- a/UI/Settings/Quality/Size/QualitySizeView.js
+++ b/UI/Settings/Quality/Size/QualitySizeView.js
@@ -2,7 +2,8 @@
 
 define([
     'app',
-    'Quality/QualitySizeCollection'
+    'Quality/QualitySizeCollection',
+    'bootstrap.slider'
 
 ], function () {
 
diff --git a/UI/Shared/Grid/HeaderCell.js b/UI/Shared/Grid/HeaderCell.js
index 27e9b88f5..00242b9fc 100644
--- a/UI/Shared/Grid/HeaderCell.js
+++ b/UI/Shared/Grid/HeaderCell.js
@@ -1,106 +1,100 @@
 "use strict";
 
-Backgrid.Column.prototype.defaults = {
-    name      : undefined,
-    label     : undefined,
-    sortable  : true,
-    editable  : false,
-    renderable: true,
-    formatter : undefined,
-    cell      : undefined,
-    headerCell: 'nzbDrone'
-};
-
-
-Backgrid.NzbDroneHeaderCell = Backgrid.HeaderCell.extend({
-    events: {
-        'click': 'onClick'
-    },
-
-    render: function () {
-        this.$el.empty();
-        this.$el.append(this.column.get("label"));
-
-        if (this.column.get('sortable')) {
-            this.$el.addClass('clickable');
-            this.$el.append(" <i class='pull-right'></i>");
-
-            if (this.collection.state) {
-                var sortKey = this.collection.state.sortKey;
-                var sortDir = this._convertIntToDirection(this.collection.state.order);
-
-                if (sortKey === this.column.get('name')) {
-                    this.$el.children('i').addClass(this._convertDirectionToIcon(sortDir));
-                    this._direction = sortDir;
-                }
-            }
-        }
-        this.delegateEvents();
-        return this;
-    },
-
-    direction: function (dir) {
-        if (arguments.length) {
-            if (this._direction) {
-                this.$el.children('i').removeClass(this._convertDirectionToIcon(this._direction));
-            }
-            if (dir) {
-                this.$el.children('i').addClass(this._convertDirectionToIcon(dir));
-            }
-            this._direction = dir;
-        }
+define(['app','backgrid'], function () {
 
-        return this._direction;
-    },
 
-    onClick: function (e) {
-        e.preventDefault();
+    Backgrid.NzbDroneHeaderCell = Backgrid.HeaderCell.extend({
+        events: {
+            'click': 'onClick'
+        },
 
-        var columnName = this.column.get("name");
+        render: function () {
+            this.$el.empty();
+            this.$el.append(this.column.get("label"));
 
-        if (this.column.get("sortable")) {
-            if (this.direction() === "ascending") {
-                this.sort(columnName, "descending", function (left, right) {
-                    var leftVal = left.get(columnName);
-                    var rightVal = right.get(columnName);
-                    if (leftVal === rightVal) {
-                        return 0;
-                    }
-                    else if (leftVal > rightVal) {
-                        return -1;
+            if (this.column.get('sortable')) {
+                this.$el.addClass('clickable');
+                this.$el.append(" <i class='pull-right'></i>");
+
+                if (this.collection.state) {
+                    var sortKey = this.collection.state.sortKey;
+                    var sortDir = this._convertIntToDirection(this.collection.state.order);
+
+                    if (sortKey === this.column.get('name')) {
+                        this.$el.children('i').addClass(this._convertDirectionToIcon(sortDir));
+                        this._direction = sortDir;
                     }
-                    return 1;
-                });
+                }
             }
-            else {
-                this.sort(columnName, "ascending", function (left, right) {
-                    var leftVal = left.get(columnName);
-                    var rightVal = right.get(columnName);
-                    if (leftVal === rightVal) {
-                        return 0;
-                    }
-                    else if (leftVal < rightVal) {
-                        return -1;
-                    }
-                    return 1;
-                });
+            this.delegateEvents();
+            return this;
+        },
+
+        direction: function (dir) {
+            if (arguments.length) {
+                if (this._direction) {
+                    this.$el.children('i').removeClass(this._convertDirectionToIcon(this._direction));
+                }
+                if (dir) {
+                    this.$el.children('i').addClass(this._convertDirectionToIcon(dir));
+                }
+                this._direction = dir;
             }
-        }
-    },
 
-    _convertDirectionToIcon: function (dir) {
-        if (dir === 'ascending') {
-            return 'icon-sort-up';
-        }
+            return this._direction;
+        },
+
+        onClick: function (e) {
+            e.preventDefault();
+
+            var columnName = this.column.get("name");
+
+            if (this.column.get("sortable")) {
+                if (this.direction() === "ascending") {
+                    this.sort(columnName, "descending", function (left, right) {
+                        var leftVal = left.get(columnName);
+                        var rightVal = right.get(columnName);
+                        if (leftVal === rightVal) {
+                            return 0;
+                        }
+                        else if (leftVal > rightVal) {
+                            return -1;
+                        }
+                        return 1;
+                    });
+                }
+                else {
+                    this.sort(columnName, "ascending", function (left, right) {
+                        var leftVal = left.get(columnName);
+                        var rightVal = right.get(columnName);
+                        if (leftVal === rightVal) {
+                            return 0;
+                        }
+                        else if (leftVal < rightVal) {
+                            return -1;
+                        }
+                        return 1;
+                    });
+                }
+            }
+        },
+
+        _convertDirectionToIcon: function (dir) {
+            if (dir === 'ascending') {
+                return 'icon-sort-up';
+            }
 
-        return 'icon-sort-down';
-    },
+            return 'icon-sort-down';
+        },
+
+        _convertIntToDirection: function (dir) {
+            if (dir === '-1') {
+                return 'ascending';
+            }
 
-    _convertIntToDirection: function (dir) {
-        if (dir === '-1') {
-            return 'ascending';
+            return 'descending';
         }
+    });
 
-        return 'descending';
-    }
+    return Backgrid.NzbDroneHeaderCell;
 });
diff --git a/UI/Shared/Grid/Pager.js b/UI/Shared/Grid/Pager.js
index 357703a43..6a8ca69ce 100644
--- a/UI/Shared/Grid/Pager.js
+++ b/UI/Shared/Grid/Pager.js
@@ -1,20 +1,8 @@
 "use strict";
-
-Backgrid.Column.prototype.defaults = {
-    name      : undefined,
-    label     : undefined,
-    sortable  : true,
-    editable  : false,
-    renderable: true,
-    formatter : undefined,
-    cell      : undefined,
-    headerCell: 'nzbDrone'
-};
-
-
 define([
     'app',
-    'JsLibraries/backbone.backgrid.paginator'
+    'backgrid',
+    'backgrid.paginator'
 ], function () {
 
     NzbDrone.Shared.Grid.Pager = Backgrid.Extension.Paginator.extend({
@@ -153,4 +141,6 @@ define([
             return this;
         }
     });
+
+    return NzbDrone.Shared.Grid.Pager;
 });
diff --git a/UI/Shared/Modal/Region.js b/UI/Shared/Modal/Region.js
index 69cf4373d..b8cd75e7c 100644
--- a/UI/Shared/Modal/Region.js
+++ b/UI/Shared/Modal/Region.js
@@ -1,6 +1,5 @@
 "use strict";
-define(function () {
-
+define(['marionette'], function () {
     return Backbone.Marionette.Region.extend({
         el: "#modal-region",
 
diff --git a/UI/app.js b/UI/app.js
index a50b06210..780593f5a 100644
--- a/UI/app.js
+++ b/UI/app.js
@@ -2,43 +2,110 @@
 require.config({
 
     paths: {
-        'backbone'  : 'JsLibraries/backbone',
-        '$'         : 'JsLibraries/jquery',
-        'underscore': 'JsLibraries/underscore',
-        'marionette': 'JsLibraries/backbone.marionette',
-        'handlebars': 'JsLibraries/handlebars',
-        'libs'      : 'JsLibraries/'
+        'backbone'          : 'JsLibraries/backbone',
+        'bootstrap'         : 'JsLibraries/bootstrap',
+        'bootstrap.slider'  : 'JsLibraries/bootstrap.slider',
+        'backbone.mutators' : 'JsLibraries/backbone.mutators',
+        'backbone.deepmodel': 'JsLibraries/backbone.deep.model',
+        'backbone.pageable' : 'JsLibraries/backbone.pageable',
+        'backgrid'          : 'JsLibraries/backbone.backgrid',
+        'backgrid.paginator': 'JsLibraries/backbone.backgrid.paginator',
+        'fullcalendar'      : 'JsLibraries/fullcalendar',
+        'backstrech'        : 'JsLibraries/jquery.backstretch',
+        '$'                 : 'JsLibraries/jquery',
+        'underscore'        : 'JsLibraries/underscore',
+        'marionette'        : 'JsLibraries/backbone.marionette',
+        'handlebars'        : 'JsLibraries/handlebars',
+        'signalR'           : 'JsLibraries/jquery.signalR',
+        'libs'              : 'JsLibraries/'
     },
 
     shim: {
-        underscore: {
-            exports: '_'
+
+        $: {
+            exports: '$'
+        },
+
+        bootstrap: {
+            deps: ['$']
+        },
+
+        'bootstrap.slider': {
+            deps: ['$']
+        },
+
+        backstrech: {
+            deps: ['$']
         },
-        backbone  : {
+
+        'underscore': {
+            dep    : ['$'],
+            exports: '_',
+            init   : function () {
+                require(['mixins/underscore.mixin.deepExtend']);
+            }
+        },
+
+        backbone: {
             deps   : ['underscore', '$'],
-            exports: 'Backbone'
+            exports: 'Backbone',
+            init   : function () {
+                require(['libs/backbone.mutators']);
+            }
         },
+
         marionette: {
             deps   : ['backbone'],
-            exports: 'Marionette'
+            exports: 'Marionette',
+            init   : function () {
+                require(['mixins/backbone.marionette.templates']);
+            }
         },
+
         handlebars: {
             exports: 'Handlebars'
         },
 
-        backbone_backgrid :{
-            exports: 'backgrid'
+        signalR: {
+            dep: ['$']
         },
 
-        backgrid  : {
-            deps: ['backbone', 'libs/backbone.backgrid', 'libs/backbone.backgrid.paginator']
+        'backbone.pageable': {
+            dep : ['backbone'],
+            init: function () {
+                console.log(this);
+            }
+        },
+
+        backgrid            : {
+            deps: ['backbone'],
+            init: function () {
+                Backgrid.Column.prototype.defaults = {
+                    name      : undefined,
+                    label     : undefined,
+                    sortable  : true,
+                    editable  : false,
+                    renderable: true,
+                    formatter : undefined,
+                    cell      : undefined,
+                    headerCell: 'nzbDrone'
+                };
+            }
+        },
+        'backgrid.paginator': {
+            deps: ['backgrid']
         }
     }
 });
 
-define(['backbone','backgrid'], function (ModalRegion) {
+define([
+    'marionette',
+    'shared/modal/region',
+    'Instrumentation/StringFormat',
+    'Instrumentation/ErrorHandler'
+], function (Marionette, ModalRegion) {
 
-    window.NzbDrone = new Backbone.Marionette.Application();
+    window.NzbDrone = new Marionette.Application();
     window.NzbDrone.Config = {};
     window.NzbDrone.Form = {};