it("supports nested scopes", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("useTabChar", "boolean", false);
     pm.definePreference("tabSize", "number", 4);
     pm.definePreference("spaceUnits", "number", 4);
     var userScope = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage());
     var projectScope = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage());
     pm.addScope("user", userScope);
     pm.addScope("project", projectScope);
     
     expect(pm.get("spaceUnits")).toEqual(4);
     
     var userLocation = {
         location: {
             scope: "user"
         }
     };
     pm.set("useTabChar", true, userLocation);
     pm.set("tabSize", 8, userLocation);
     pm.set("spaceUnits", 8, userLocation);
     pm.set("spaceUnits", 2, {
         location: {
             scope: "project"
         }
     });
     
     expect(pm.get("spaceUnits")).toBe(2);
     expect(pm.get("useTabChar")).toBe(true);
     expect(pm.get("tabSize")).toBe(8);
 });
 it("should yield an error if a preference is redefined", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("foo.bar", "string");
     try {
         pm.definePreference("foo.bar", "string");
         expect("We should have gotten an exception").toEqual("but we didn't");
     } catch (e) {
     }
 });
 it("can notify changes for single preference objects", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     var pref = pm.definePreference("spaceUnits", "number", 4);
     var retrievedPref = pm.getPreference("spaceUnits");
     expect(retrievedPref).toBe(pref);
     var changes = 0;
     pref.on("change", function (e) {
         changes++;
     });
     var newScope = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage({
         spaceUnits: 2
     }));
     pm.addScope("new", newScope);
     expect(changes).toEqual(1);
     
     pref.off("change");
     pm.set("spaceUnits", 10, {
         location: {
             scope: "new"
         }
     });
     expect(changes).toEqual(1);
     
     changes = 0;
     pm.on("change", "spaceUnits", function () {
         changes++;
     });
     pm.set("spaceUnits", 11, {
         location: {
             scope: "new"
         }
     });
     expect(changes).toEqual(1);
 });
 it("can notify of preference changes via scope changes and scope changes", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("spaceUnits", "number", 4);
     
     var eventData = [],
         scopeEvents = [];
     
     pm.on("change", function (e, data) {
         eventData.push(data);
     });
     
     pm.on("scopeOrderChange", function (e, data) {
         scopeEvents.push(data);
     });
     
     pm.addScope("user", new PreferencesBase.MemoryStorage({
         spaceUnits: 4,
         elephants: "charging"
     }));
     
     expect(pm._defaultContext.scopeOrder).toEqual(["user", "default"]);
     
     expect(eventData).toEqual([{
         ids: ["spaceUnits", "elephants"]
     }]);
     
     expect(scopeEvents).toEqual([{
         id: "user",
         action: "added"
     }]);
     
     scopeEvents = [];
     eventData = [];
     pm.removeScope("user");
     expect(pm._defaultContext.scopeOrder).toEqual(["default"]);
     expect(eventData).toEqual([{
         ids: ["spaceUnits", "elephants"]
     }]);
     
     expect(scopeEvents).toEqual([{
         id: "user",
         action: "removed"
     }]);
 });
 it("can notify of preference changes through set", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("spaceUnits", "number", 4);
     pm.addScope("user", new PreferencesBase.MemoryStorage());
     var eventData;
     pm.on("change", function (e, data) {
         eventData = data;
     });
     
     pm.set("testing", true);
     expect(eventData).toEqual({
         ids: ["testing"]
     });
     
     eventData = undefined;
     pm.set("spaceUnits", 4);
     expect(eventData).toEqual({
         ids: ["spaceUnits"]
     });
 });
 it("handles asynchronously loaded scopes", function () {
     var storage1 = new PreferencesBase.MemoryStorage({
         testKey: 1
     });
     
     var deferred1 = $.Deferred();
     storage1.load = function () {
         return deferred1;
     };
     
     var storage2 = new PreferencesBase.MemoryStorage({
         testKey: 2
     });
     
     var deferred2 = $.Deferred();
     storage2.load = function () {
         return deferred2;
     };
     
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("testKey", "number", 0);
     pm.addScope("storage1", new PreferencesBase.Scope(storage1), {
         before: "storage2"
     });
     pm.addScope("storage2", new PreferencesBase.Scope(storage2), {
         before: "default"
     });
     
     expect(pm.get("testKey")).toBe(0);
     
     deferred1.resolve(storage1.data);
     expect(pm.get("testKey")).toBe(0);
     
     deferred2.resolve(storage2.data);
     expect(pm.get("testKey")).toBe(1);
 });
 it("can set preference values at any level", function () {
     var pm = new PreferencesBase.PreferencesSystem(),
         pref = pm.definePreference("spaceUnits", "number", 4),
         user = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage()),
         project = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage({
             path: {
                 "**.html": {
                     spaceUnits: 2
                 }
             }
         })),
         session = new PreferencesBase.Scope(new PreferencesBase.MemoryStorage());
     
     project.addLayer(new PreferencesBase.PathLayer("/"));
     pm.addScope("user", user);
     pm.addScope("project", project);
     pm.addScope("session", session);
     
     var changes = 0;
     pref.on("change", function (e) {
         changes++;
     });
     
     expect(pm.set("spaceUnits", 5, {
         location: {
             scope: "doesNotExist"
         }
     })).toBe(false);
     expect(pm.get("spaceUnits")).toBe(4);
     expect(changes).toBe(0);
     expect(pm.getPreferenceLocation("spaceUnits")).toEqual({
         scope: "default"
     });
     
     expect(pm.set("spaceUnits", 6)).toBe(true);
     expect(user.data).toEqual({
         spaceUnits: 6
     });
     expect(changes).toBe(1);
     
     expect(pm.set("spaceUnits", 7)).toBe(true);
     expect(user.data).toEqual({
         spaceUnits: 7
     });
     expect(changes).toBe(2);
     
     expect(pm.set("spaceUnits", 8, {
         location: {
             scope: "session"
         }
     })).toBe(true);
     expect(user.data).toEqual({
         spaceUnits: 7
     });
     expect(session.data).toEqual({
         spaceUnits: 8
     });
     expect(changes).toBe(3);
     
     expect(pm.set("spaceUnits", 9)).toBe(true);
     expect(changes).toBe(4);
     expect(session.data).toEqual({
         spaceUnits: 9
     });
     
     expect(pm.set("spaceUnits", undefined, {
         location: {
             scope: "session"
         }
     })).toBe(true);
     expect(changes).toBe(5);
     expect(session.data.spaceUnits).toBeUndefined();
     expect(pm.get("spaceUnits")).toBe(7);
     expect(Object.keys(session.data)).toEqual([]);
     
     pm.setDefaultFilename("/index.html");
     expect(changes).toBe(6);
     expect(pm.get("spaceUnits")).toBe(2);
     expect(pm.set("spaceUnits", 10)).toBe(true);
     expect(changes).toBe(7);
     expect(project.data.path["**.html"].spaceUnits).toBe(10);
     
     pm.setDefaultFilename("/foo.txt");
     expect(pm.getPreferenceLocation("spaceUnits")).toEqual({
         scope: "user"
     });
     expect(pm.set("spaceUnits", 11, {
         location: {
             scope: "project"
         }
     })).toBe(true);
     expect(pm.getPreferenceLocation("spaceUnits")).toEqual({
         scope: "project"
     });
     expect(pm.set("spaceUnits", 12)).toBe(true);
     expect(project.data.spaceUnits).toBe(12);
     
     expect(pm.set("spaceUnits", 13, {
         location: {
             scope: "project",
             layer: "path",
             layerID: "**.js"
         }
     })).toBe(true);
     expect(pm.getPreferenceLocation("spaceUnits")).toEqual({
         scope: "project"
     });
     
     var context = pm.buildContext({
         filename: "/Gruntfile.js"
     });
     expect(pm.getPreferenceLocation("spaceUnits", context)).toEqual({
         scope: "project",
         layer: "path",
         layerID: "**.js"
     });
     expect(pm.get("spaceUnits", context)).toBe(13);
 });
 it("should find the default values", function () {
     var pm = new PreferencesBase.PreferencesSystem();
     pm.definePreference("foo.bar", "number", 0);
     expect(pm.get("nonexistent")).toBeUndefined();
     expect(pm.get("foo.bar")).toBe(0);
 });