<commit_before>// Category View
// =============

// Includes file dependencies
define([
    "jquery",
    "backbone",
    "moment",
    "text!../templates/character-print-view.html",
    "text!../templates/character-approval-view.html",
    "../collections/Approvals",
    "../models/Approval",
    "text!../templates/character-approval-selected-view.html",
    "../helpers/VampirePrintHelper",
    "text!../templates/character-approval-edit.html"
], function( $,
             Backbone,
             moment,
             character_print_view_html,
             character_approval_view_html,
             Approvals,
             Approval,
             character_approval_selected_view_html,
             VampirePrintHelper,
             character_approval_edit_html) {

    // Extends Backbone.View
    var View = Backbone.View.extend( {

        // The View Constructor
        initialize: function() {
            var self = this;

            _.bindAll(this,
                "render",
                "format_simpletext",
                "format_attribute_value",
                "format_attribute_focus",
                "format_skill",
                "format_specializations"
            );

            self.sheetTemplate = _.template(character_print_view_html);
            self.approvalSelectedTemplate = _.template(character_approval_selected_view_html);
            self.editTemplate = _.template(character_approval_edit_html);
        },

        register: function(character) {
            var self = this;
            var p = Parse.Promise.as([]);

            if (character !== self.character) {
                if (self.character) {
                    self.stopListening(self.character);
                    if (self.character.recorded_changes) {
                        self.stopListening(self.character.recorded_changes);
                    }
                }
                self.character = character;

                self.approvals = new Approvals;
                var q = new Parse.Query(Approval);
                q.equalTo("owner", self.character);
                self.approvals.query = q;
                p = q.each(function (approval) {
                    self.approvals.add(approval);
                    self.approval_index = self.approvals.length;
                });
                p.then(function () {
                    return self.character.get_recorded_changes(function (rc) {
                        self.listenTo(rc, "add", self.render);
                        self.listenTo(rc, "reset", self.render);
                        if (self.character.recorded_changes.length > 0) {
                            _.defer(self.render);
                        }
                    });
                });
            }

            return p.then(function () {
                Parse.Promise.as(self);
            });
        },

        events: {
            "change #slider": "update_selected",
            "change #sliderbaserange": "update_base_selected",
            "change #approval-slider": "update_approval_selected",
            "click .approve-change": "approve_change"
        },

        approve_change: function() {
            var self = this;
            var change = self.character.recorded_changes.at(self.indexForPickedChange);
            var a = new Approval({
                approved: true,
                change: change,
                approver: Parse.User.current(),
                owner: self.character
            });
            a.save().then(function (approval) {
                self.approvals.add(approval);
                self.approval_index = self.approvals.length;
                self.indexForPickedChange = self.character.recorded_changes.models.length - 1;
                return self.render();
            });
        },

        format_entry: function(log, entry) {
            if (_.isUndefined(log)) {
                console.log("Undefined log");
                return "Undefined log";
            }
            if (log.get(entry)) {
                return log.get(entry);
            }
            var attr = log[entry];
            if (_.isDate(attr)) {
                return moment(attr).format('lll');
            }
            return attr;
        },

        format_approval: function(approval, h) {
            var sub = approval.get(h);
            if (_.isUndefined(sub)) {
                return _.result(approval, h);
            }
            if (_.has(sub, "id")) {
                return sub.id;
            }
            return sub;
        },

        _update_approval_selected: function (approval_index) {
            var self = this;
            self.approval_index = approval_index;
            self.approved = self.approvals.models[self.approval_index];
            self.left_approval_index = self.approval_index - 1
            if (self.left_approval_index >= 0) {
                self.left_approved = self.approvals.models[self.left_approval_index];
            } else {
                self.left_approved = null;
            }

            var selectedIndex = 0;
            if (self.approval_index < self.approvals.length) {
                var change = _.findLast(self.character.recorded_changes.models, function (model, i) {
                    if (model.id == self.approved.get("change").id) {
                        selectedIndex = i;
                        return true;
                    }
                    return false;
                })
            } else {
                selectedIndex = self.character.recorded_changes.length - 1;
            }
            self.indexForPickedChange = selectedIndex;
            if (self.left_approval_index >= 0) {
                _.findLast(self.character.recorded_changes.models, function (model, i) {
                    if (model.id == self.left_approved.get("change").id) {
                        self.left_rc_index = i + 1;
                        return true;
                    }
                    return false;
                });
            } else {
                self.left_rc_index = 0;
            }

            self.$("#sliderbaserange").val(self.left_rc_index).slider('refresh');
            self.$("#slider").val(selectedIndex).slider('refresh');

            return change || _.last(self.character.recorded_changes.models);
        },

        _get_display_character: function(id) {
            var self = this;
            var changesToApply = _.chain(self.character.recorded_changes.models).takeRightWhile(function (model) {
                return model.id != id;
            }).reverse().value();
            var c = self.character.get_transformed(changesToApply);
            if (self.transform_description) {
                // Add back any removed traits
                var a = _(self.transform_description).select({type: "removed"}).value();
                _.each(a, function (trait) {
                    trait.fake.is_deleted = true;
                    c.set(trait.category, _.union(c.get(trait.category), [trait.fake]));
                });
            }
            return c;
        },

        update_approval_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            var change = self._update_approval_selected(selectedIndex);
            self._update_transform_description(self.left_rc_index);

            self._render_viewing(true);
            self._render_edit(true);

            var c = self._get_display_character(change.id);
            self._render_sheet(c, true);
        },

        update_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            self.indexForPickedChange = selectedIndex;
            self._update_transform_description(self.left_rc_index);
            self._render_viewing(true);
            self._render_edit(true);

            var selectedId = this.$("#history-changes-" + selectedIndex).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c, true);
        },

        _update_transform_description: function(selectedIndex) {
            var self = this;
            var changesToApply = _.chain(self.character.recorded_changes.models)
                .takeRightWhile(function (model, i) {
                    return i != selectedIndex - 1;
                })
                .reverse()
                .value();
            var c = self.character.get_transformed(changesToApply);
            self.transform_description = _.takeRight(c.transform_description, (self.indexForPickedChange + 1) - selectedIndex);
        },

        update_base_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            self.left_rc_index = selectedIndex;
            self._update_transform_description(self.left_rc_index);
            self._render_viewing(true);
            self._render_edit(true);

            var selectedId = this.$("#history-changes-" + self.indexForPickedChange).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c);
        },

        _render_edit: function(enhance) {
            var self = this;
            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }
            this.$el.find("#approval-edit").html(this.editTemplate({
                "character": this.character,
                "logs": self.character.recorded_changes.models,
                "format_entry": this.format_entry,
                "format_approval": this.format_approval,
                indexForPickedChange: sendId,
                left_rc_index: self.left_rc_index,
                approval_index: self.approval_index,
                approvals: self.approvals.models,
                approval: self.approvals.models[self.approval_index]
            }));
            if (enhance) {
                this.$el.find("#approval-edit").enhanceWithin();
            }
        },

        _render_viewing: function(enhance) {
            var self = this;
            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }
            this.$el.find("#approval-viewing").html(this.approvalSelectedTemplate({
                "character": this.character,
                "logs": self.character.recorded_changes.models,
                "format_entry": this.format_entry,
                "format_approval": this.format_approval,
                indexForPickedChange: sendId,
                left_rc_index: self.left_rc_index,
                approval_index: self.approval_index,
                approvals: self.approvals.models,
                approval: self.approvals.models[self.approval_index]
            }));
            if (enhance) {
                this.$el.find("#approval-viewing").enhanceWithin();
            }
        },

        _render_sheet: function(characterOverride, enhance) {
            var self = this;
            self.character_override = characterOverride || self.character;
            var c = self.character_override;
            var sortedSkills = c.get_sorted_skills();
            var groupedSkills = c.get_grouped_skills(sortedSkills, 3);
            this.$el.find("#approval-sheet").html(this.sheetTemplate({
                "character": c,
                "skills": sortedSkills,
                "groupedSkills": groupedSkills,
                "transform_description": self.transform_description,
                format_simpletext: this.format_simpletext,
                format_attribute_value: this.format_attribute_value,
                format_attribute_focus: this.format_attribute_focus,
                format_skill: this.format_skill,
                format_specializations: this.format_specializations,
            }));
            if (enhance) {
                this.$el.find("#approval-sheet").enhanceWithin();
            }
        },

        // Renders all of the Category models on the UI
        render: function() {
            var self = this;

            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }

            self._update_approval_selected(self.approvals.length);
            self._update_transform_description(self.left_rc_index);

            // Sets the view's template property
            this.template = _.template(character_approval_view_html)({
                    "character": this.character,
                    "logs": this.character.recorded_changes.models,
                    "format_entry": this.format_entry,
                    "format_approval": this.format_approval,
                    indexForPickedChange: sendId,
                    left_rc_index: self.left_rc_index,
                    approval_index: self.approval_index,
                    approvals: self.approvals.models,
                    approval: self.approvals.models[self.approval_index]
                 });

            /*
            _.each(self.approvals.models[self.approval_index], function (approval, i) {
                var headers = ["approved", "change", "approver", "owner"];
                _.each(headers, function (h) {
                    console.log(approval.get(h));
                });
            });
            */
            // Renders the view's template inside of the current listview element
            this.$el.find("#approval-main").html(this.template);

            this._render_viewing();
            this._render_edit();

            var selectedId = this.$("#history-changes-" + self.indexForPickedChange).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c);

            this.$el.enhanceWithin();

            // Maintains chainability
            return this;

        }

    } );

    _.extend(View.prototype, VampirePrintHelper);

    // Returns the View class
    return View;

} );<commit_msg>Support one-length ranges<commit_after>// Category View
// =============

// Includes file dependencies
define([
    "jquery",
    "backbone",
    "moment",
    "text!../templates/character-print-view.html",
    "text!../templates/character-approval-view.html",
    "../collections/Approvals",
    "../models/Approval",
    "text!../templates/character-approval-selected-view.html",
    "../helpers/VampirePrintHelper",
    "text!../templates/character-approval-edit.html"
], function( $,
             Backbone,
             moment,
             character_print_view_html,
             character_approval_view_html,
             Approvals,
             Approval,
             character_approval_selected_view_html,
             VampirePrintHelper,
             character_approval_edit_html) {

    // Extends Backbone.View
    var View = Backbone.View.extend( {

        // The View Constructor
        initialize: function() {
            var self = this;

            _.bindAll(this,
                "render",
                "format_simpletext",
                "format_attribute_value",
                "format_attribute_focus",
                "format_skill",
                "format_specializations"
            );

            self.sheetTemplate = _.template(character_print_view_html);
            self.approvalSelectedTemplate = _.template(character_approval_selected_view_html);
            self.editTemplate = _.template(character_approval_edit_html);
        },

        register: function(character) {
            var self = this;
            var p = Parse.Promise.as([]);

            if (character !== self.character) {
                if (self.character) {
                    self.stopListening(self.character);
                    if (self.character.recorded_changes) {
                        self.stopListening(self.character.recorded_changes);
                    }
                }
                self.character = character;

                self.approvals = new Approvals;
                var q = new Parse.Query(Approval);
                q.equalTo("owner", self.character);
                self.approvals.query = q;
                p = q.each(function (approval) {
                    self.approvals.add(approval);
                    self.approval_index = self.approvals.length;
                });
                p.then(function () {
                    return self.character.get_recorded_changes(function (rc) {
                        self.listenTo(rc, "add", self.render);
                        self.listenTo(rc, "reset", self.render);
                        if (self.character.recorded_changes.length > 0) {
                            _.defer(self.render);
                        }
                    });
                });
            }

            return p.then(function () {
                Parse.Promise.as(self);
            });
        },

        events: {
            "change #slider": "update_selected",
            "change #sliderbaserange": "update_base_selected",
            "change #approval-slider": "update_approval_selected",
            "click .approve-change": "approve_change"
        },

        approve_change: function() {
            var self = this;
            var change = self.character.recorded_changes.at(self.indexForPickedChange);
            var a = new Approval({
                approved: true,
                change: change,
                approver: Parse.User.current(),
                owner: self.character
            });
            a.save().then(function (approval) {
                self.approvals.add(approval);
                self.approval_index = self.approvals.length;
                self.indexForPickedChange = self.character.recorded_changes.models.length - 1;
                return self.render();
            });
        },

        format_entry: function(log, entry) {
            if (_.isUndefined(log)) {
                console.log("Undefined log");
                return "Undefined log";
            }
            if (log.get(entry)) {
                return log.get(entry);
            }
            var attr = log[entry];
            if (_.isDate(attr)) {
                return moment(attr).format('lll');
            }
            return attr;
        },

        format_approval: function(approval, h) {
            var sub = approval.get(h);
            if (_.isUndefined(sub)) {
                return _.result(approval, h);
            }
            if (_.has(sub, "id")) {
                return sub.id;
            }
            return sub;
        },

        _update_approval_selected: function (approval_index) {
            var self = this;
            self.approval_index = approval_index;
            self.approved = self.approvals.models[self.approval_index];
            self.left_approval_index = self.approval_index - 1
            if (self.left_approval_index >= 0) {
                self.left_approved = self.approvals.models[self.left_approval_index];
            } else {
                self.left_approved = null;
            }

            var selectedIndex = 0;
            if (self.approval_index < self.approvals.length) {
                var change = _.findLast(self.character.recorded_changes.models, function (model, i) {
                    if (model.id == self.approved.get("change").id) {
                        selectedIndex = i;
                        return true;
                    }
                    return false;
                })
            } else {
                selectedIndex = self.character.recorded_changes.length - 1;
            }
            self.indexForPickedChange = selectedIndex;
            if (self.left_approval_index >= 0) {
                _.findLast(self.character.recorded_changes.models, function (model, i) {
                    if (model.id == self.left_approved.get("change").id) {
                        self.left_rc_index = i + 1;
                        return true;
                    }
                    return false;
                });
            } else {
                self.left_rc_index = 0;
            }

            self.$("#slider").val(selectedIndex).slider('refresh');
            self.$("#sliderbaserange").val(self.left_rc_index).slider('refresh');

            return change || _.last(self.character.recorded_changes.models);
        },

        _get_display_character: function(id) {
            var self = this;
            var changesToApply = _.chain(self.character.recorded_changes.models).takeRightWhile(function (model) {
                return model.id != id;
            }).reverse().value();
            var c = self.character.get_transformed(changesToApply);
            if (self.transform_description) {
                // Add back any removed traits
                var a = _(self.transform_description).select({type: "removed"}).value();
                _.each(a, function (trait) {
                    trait.fake.is_deleted = true;
                    c.set(trait.category, _.union(c.get(trait.category), [trait.fake]));
                });
            }
            return c;
        },

        update_approval_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            var change = self._update_approval_selected(selectedIndex);
            self._update_transform_description(self.left_rc_index);

            self._render_viewing(true);
            self._render_edit(true);

            var c = self._get_display_character(change.id);
            self._render_sheet(c, true);
        },

        update_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            self.indexForPickedChange = selectedIndex;
            self._update_transform_description(self.left_rc_index);
            self._render_viewing(true);
            self._render_edit(true);

            var selectedId = this.$("#history-changes-" + selectedIndex).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c, true);
        },

        _update_transform_description: function(selectedIndex) {
            var self = this;
            var changesToApply = _.chain(self.character.recorded_changes.models)
                .takeRightWhile(function (model, i) {
                    return i != selectedIndex - 1;
                })
                .reverse()
                .value();
            var c = self.character.get_transformed(changesToApply);
            self.transform_description = _.takeRight(c.transform_description, (self.indexForPickedChange + 1) - selectedIndex);
        },

        update_base_selected: function (e) {
            var self = this;
            var selectedIndex = _.parseInt(this.$(e.target).val());
            self.left_rc_index = selectedIndex;
            self._update_transform_description(self.left_rc_index);
            self._render_viewing(true);
            self._render_edit(true);

            var selectedId = this.$("#history-changes-" + self.indexForPickedChange).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c);
        },

        _render_edit: function(enhance) {
            var self = this;
            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }
            this.$el.find("#approval-edit").html(this.editTemplate({
                "character": this.character,
                "logs": self.character.recorded_changes.models,
                "format_entry": this.format_entry,
                "format_approval": this.format_approval,
                indexForPickedChange: sendId,
                left_rc_index: self.left_rc_index,
                approval_index: self.approval_index,
                approvals: self.approvals.models,
                approval: self.approvals.models[self.approval_index]
            }));
            if (enhance) {
                this.$el.find("#approval-edit").enhanceWithin();
            }
        },

        _render_viewing: function(enhance) {
            var self = this;
            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }
            this.$el.find("#approval-viewing").html(this.approvalSelectedTemplate({
                "character": this.character,
                "logs": self.character.recorded_changes.models,
                "format_entry": this.format_entry,
                "format_approval": this.format_approval,
                indexForPickedChange: sendId,
                left_rc_index: self.left_rc_index,
                approval_index: self.approval_index,
                approvals: self.approvals.models,
                approval: self.approvals.models[self.approval_index]
            }));
            if (enhance) {
                this.$el.find("#approval-viewing").enhanceWithin();
            }
        },

        _render_sheet: function(characterOverride, enhance) {
            var self = this;
            self.character_override = characterOverride || self.character;
            var c = self.character_override;
            var sortedSkills = c.get_sorted_skills();
            var groupedSkills = c.get_grouped_skills(sortedSkills, 3);
            this.$el.find("#approval-sheet").html(this.sheetTemplate({
                "character": c,
                "skills": sortedSkills,
                "groupedSkills": groupedSkills,
                "transform_description": self.transform_description,
                format_simpletext: this.format_simpletext,
                format_attribute_value: this.format_attribute_value,
                format_attribute_focus: this.format_attribute_focus,
                format_skill: this.format_skill,
                format_specializations: this.format_specializations,
            }));
            if (enhance) {
                this.$el.find("#approval-sheet").enhanceWithin();
            }
        },

        // Renders all of the Category models on the UI
        render: function() {
            var self = this;

            var sendId = self.indexForPickedChange;
            if (_.isUndefined(sendId)) {
                sendId = self.character.recorded_changes.models.length - 1;
            }

            self._update_approval_selected(self.approvals.length);
            self._update_transform_description(self.left_rc_index);

            // Sets the view's template property
            this.template = _.template(character_approval_view_html)({
                    "character": this.character,
                    "logs": this.character.recorded_changes.models,
                    "format_entry": this.format_entry,
                    "format_approval": this.format_approval,
                    indexForPickedChange: sendId,
                    left_rc_index: self.left_rc_index,
                    approval_index: self.approval_index,
                    approvals: self.approvals.models,
                    approval: self.approvals.models[self.approval_index]
                 });

            /*
            _.each(self.approvals.models[self.approval_index], function (approval, i) {
                var headers = ["approved", "change", "approver", "owner"];
                _.each(headers, function (h) {
                    console.log(approval.get(h));
                });
            });
            */
            // Renders the view's template inside of the current listview element
            this.$el.find("#approval-main").html(this.template);

            this._render_viewing();
            this._render_edit();

            var selectedId = this.$("#history-changes-" + self.indexForPickedChange).val();
            var c = self._get_display_character(selectedId);
            self._render_sheet(c);

            this.$el.enhanceWithin();

            // Maintains chainability
            return this;

        }

    } );

    _.extend(View.prototype, VampirePrintHelper);

    // Returns the View class
    return View;

} );<|endoftext|>


<commit_before>
// Sparky.observe()
// Sparky.unobserve()

(function(Sparky) {
	"use strict";

	// Handle paths

	var rpathtrimmer = /^\[|]$/g;
	var rpathsplitter = /\]?\.|\[/g;
	var map = [];

	function noop() {}
	function isDefined(val) { return val !== undefined && val !== null; }
	function isObject(obj) { return obj instanceof Object; }

	function splitPath(path) {
		return path
			.replace(rpathtrimmer, '')
			.split(rpathsplitter);
	}

	function objFrom(obj, array) {
		var key = array.shift();
		var val = obj[key];

		return array.length === 0 ? val :
			isDefined(val) ? objFrom(val, array) :
			val ;
	}

	function objTo(root, array, obj) {
		var key = array[0];

		return array.length > 1 ?
			objTo(isObject(root[key]) ? root[key] : (root[key] = {}), array.slice(1), obj) :
			(root[key] = obj) ;
	}

	function observePath3(root, prop, array, fn, notify) {
		function update() {
			Sparky.logVerbose('path resolved to value:', root[prop]);
			fn(root[prop]);
		}

		Sparky.observe(root, prop, update, notify);

		return function unobserve() {
			Sparky.unobserve(root, prop, update);
		};
	}

	function observePath2(root, prop, array, fn, notify) {
		var destroy = noop;

		function update() {
			var object = root[prop];

			destroy();

			if (typeof object !== 'object' && typeof object !== 'function') {
				destroy = noop;
				if (notify) { fn(); }
			}
			else {
				destroy = observePath1(object, array.slice(), fn, notify) ;
			}
		};

		Sparky.observe(root, prop, update, true);
		notify = true;

		return function unobserve() {
			destroy();
			Sparky.unobserve(root, prop, update);
		};
	}

	function observePath1(root, array, fn, notify) {
		if (array.length === 0) { return noop; }

		var prop = array.shift();

		return array.length === 0 ?
			observePath3(root, prop, array, fn, notify) :
			observePath2(root, prop, array, fn, notify) ;
	}

	function observePath(root, path, fn, immediate) {
		var array = splitPath(path);

		// Observe path without logs.
		var destroy = observePath1(root, array, fn, immediate || false) ;

		// Register this binding in a map
		map.push([root, path, fn, destroy]);
	}

	function observePathOnce(root, path, fn) {
		var array = splitPath(path);
		var value = objFrom(root, array.slice());

		if (isDefined(value)) {
			fn(value);
			return;
		}

		var destroy = observePath1(root, array, update, false);

		// Hack around the fact that the first call to destroy()
		// is not ready yet, becuase at the point update has been
		// called by the observe recursers, the destroy fn has
		// not been returned yet. TODO: we should make direct returns
		// async to get around this - they would be async if they were
		// using Object.observe after all...
		var hasRun = false;

		function update(value) {
			if (hasRun) { return; }
			if (isDefined(value)) {
				hasRun = true;
				fn(value);
				setTimeout(function() {
					unobservePath(root, path, fn);
				}, 0);
			}
		}

		// Register this binding in a map
		map.push([root, path, fn, destroy]);
	}

	function unobservePath(root, path, fn) {
		var n = map.length;
		var record;

		// Allow for the call signatures (root) and (root, fn)
		if (typeof path !== 'string') {
			fn = path;
			path = undefined;
		}

		while (n--) {
			record = map[n];
			if ((root === record[0]) &&
				(!path || path === record[1]) &&
				(!fn || fn === record[2])) {
				record[3]();
				map.splice(n, 1);
			}
		}
	}

	function getPath(obj, path) {
		return obj && (path === '.' ?
			obj :
			objFrom(obj, splitPath(path)));
	}

	function setPath(root, path, obj) {
		var array = splitPath(path);

		return array.length === 1 ?
			(root[path] = obj) :
			objTo(root, array, obj);
	}

	Sparky.get = getPath;
	Sparky.set = setPath;
	Sparky.observePath = observePath;
	Sparky.unobservePath = unobservePath;
	Sparky.observePathOnce = observePathOnce;

	// Binding

	function isAudioParam(object) {
		return window.AudioParam && window.AudioParam.prototype.isPrototypeOf(object);
	}

	function Poll(object, property, fn) {
		var v1 = object[property];
		var active = true;

		function frame() {
			var v2 = object[property];

			if (v1 !== v2) {
				v1 = v2;
				fn();
			}

			if (!active) { return; }

			window.requestAnimationFrame(frame);
		};

		function cancel() {
			active = false;
		}

		window.requestAnimationFrame(frame);
		return cancel;
	}

	var unpollers = [];

	function poll(object, property, fn) {
		unpollers.push([object, property, fn, Poll(object, property, fn)]);
		return object;
	}

	function unpoll(object, property, fn) {
		var n = unpollers.length;
		var unpoller;

		while (n--) {
			unpoller = unpollers[n];

			if (object === unpoller[0] && property === unpoller[1] && fn === unpoller[2]) {
				unpoller[3]();
				unpollers.splice(n, 1);
				return object;
			}
		}

		return object;
	}

	(false && Object.observe && window.WeakMap ? function(Sparky) {
		if (Sparky.debug) { console.log('Sparky: Ooo. Lucky you, using Object.observe and WeakMap.'); }

		var map = new WeakMap();
		var names = [];
		var types = ["add", "update", "delete"];

		function call(fn) {
			fn(this);
		}

		function trigger(change) {
			var properties = this;
			var name = change.name;
			var object = change.object;

			// If this property is in the properties being watched, and we
			// have not already called changes on it, do that now.
			if (properties[name] && names.indexOf(name) === -1) {
				names.push(name);
				fns = properties[name];
				fns.forEach(call, object);
			}
		}

		function triggerAll(changes) {
			names.length = 0;
			changes.forEach(trigger, map[object]);
		}

		function setup(object) {
			var properties = map[object] = {};
			Object.observe(object, triggerAll, types);
			return properties;
		}

		function teardown(object) {
			Object.unobserve(object, triggerAll);
		}

		Sparky.observe = function(object, property, fn) {
			var properties = map[object] || setup(object);
			var fns = properties[property] || (properties[property] = []);
			fns.push(fn);
		};

		Sparky.unobserve = function(object, property, fn) {
			if (!map[object]) { return; }

			var properties = map[object];
			var fns = properties[property];

			if (!fns) { return; }

			var n = fns.length;

			while (n--) { fns.splice(n, 1); }

			if (fns.length === 0) {
				delete properties[property];

				if (Object.keys[properties].length === 0) {
					teardown(object);
				}
			}
		};
	} : function(Sparky) {
		Sparky.observe = function(object, property, fn, immediate) {
			// AudioParams objects must be polled, as they cannot be reconfigured
			// to getters/setters, nor can they be Object.observed. And they fail
			// to do both of those completely silently. So we test the scope to see
			// if it is an AudioParam and set the observe and unobserve functions
			// to poll.
			if (isAudioParam(object)) {
				return poll(object, property, fn);
			}

			if (property === 'length') {
				// Observe length and update the DOM on next
				// animation frame if it changes.
				var descriptor = Object.getOwnPropertyDescriptor(object, property);

				if (!descriptor.get && !descriptor.configurable) {
					console.warn && console.warn('Sparky: Are you trying to observe an array?. Sparky is going to observe it by polling. You may want to use a Collection() to avoid this.', object, object instanceof Array);
					console.trace && console.trace();
					return poll(object, property, fn);
				}
			}

			observe(object, property, fn);
			if (immediate) { fn(object); }
		};

		Sparky.unobserve = function(object, property, fn) {
			if (isAudioParam(object)) {
				return unpoll(object, property, fn);
			}

			if (property === 'length') {
				var descriptor = Object.getOwnPropertyDescriptor(object, property);
				if (!descriptor.get && !descriptor.configurable) {
					return unpoll(object, property, fn);
				}
			}

			return unobserve(object, property, fn);
		};
	})(Sparky)
})(Sparky);
<commit_msg>Throw error when Sparky.observe called without object<commit_after>
// Sparky.observe()
// Sparky.unobserve()

(function(Sparky) {
	"use strict";

	// Handle paths

	var rpathtrimmer = /^\[|]$/g;
	var rpathsplitter = /\]?\.|\[/g;
	var map = [];

	function noop() {}
	function isDefined(val) { return val !== undefined && val !== null; }
	function isObject(obj) { return obj instanceof Object; }

	function splitPath(path) {
		return path
			.replace(rpathtrimmer, '')
			.split(rpathsplitter);
	}

	function objFrom(obj, array) {
		var key = array.shift();
		var val = obj[key];

		return array.length === 0 ? val :
			isDefined(val) ? objFrom(val, array) :
			val ;
	}

	function objTo(root, array, obj) {
		var key = array[0];

		return array.length > 1 ?
			objTo(isObject(root[key]) ? root[key] : (root[key] = {}), array.slice(1), obj) :
			(root[key] = obj) ;
	}

	function observePath3(root, prop, array, fn, notify) {
		function update() {
			Sparky.logVerbose('path resolved to value:', root[prop]);
			fn(root[prop]);
		}

		Sparky.observe(root, prop, update, notify);

		return function unobserve() {
			Sparky.unobserve(root, prop, update);
		};
	}

	function observePath2(root, prop, array, fn, notify) {
		var destroy = noop;

		function update() {
			var object = root[prop];

			destroy();

			if (typeof object !== 'object' && typeof object !== 'function') {
				destroy = noop;
				if (notify) { fn(); }
			}
			else {
				destroy = observePath1(object, array.slice(), fn, notify) ;
			}
		};

		Sparky.observe(root, prop, update, true);
		notify = true;

		return function unobserve() {
			destroy();
			Sparky.unobserve(root, prop, update);
		};
	}

	function observePath1(root, array, fn, notify) {
		if (array.length === 0) { return noop; }

		var prop = array.shift();

		return array.length === 0 ?
			observePath3(root, prop, array, fn, notify) :
			observePath2(root, prop, array, fn, notify) ;
	}

	function observePath(root, path, fn, immediate) {
		var array = splitPath(path);

		// Observe path without logs.
		var destroy = observePath1(root, array, fn, immediate || false) ;

		// Register this binding in a map
		map.push([root, path, fn, destroy]);
	}

	function observePathOnce(root, path, fn) {
		var array = splitPath(path);
		var value = objFrom(root, array.slice());

		if (isDefined(value)) {
			fn(value);
			return;
		}

		var destroy = observePath1(root, array, update, false);

		// Hack around the fact that the first call to destroy()
		// is not ready yet, becuase at the point update has been
		// called by the observe recursers, the destroy fn has
		// not been returned yet. TODO: we should make direct returns
		// async to get around this - they would be async if they were
		// using Object.observe after all...
		var hasRun = false;

		function update(value) {
			if (hasRun) { return; }
			if (isDefined(value)) {
				hasRun = true;
				fn(value);
				setTimeout(function() {
					unobservePath(root, path, fn);
				}, 0);
			}
		}

		// Register this binding in a map
		map.push([root, path, fn, destroy]);
	}

	function unobservePath(root, path, fn) {
		var n = map.length;
		var record;

		// Allow for the call signatures (root) and (root, fn)
		if (typeof path !== 'string') {
			fn = path;
			path = undefined;
		}

		while (n--) {
			record = map[n];
			if ((root === record[0]) &&
				(!path || path === record[1]) &&
				(!fn || fn === record[2])) {
				record[3]();
				map.splice(n, 1);
			}
		}
	}

	function getPath(obj, path) {
		return obj && (path === '.' ?
			obj :
			objFrom(obj, splitPath(path)));
	}

	function setPath(root, path, obj) {
		var array = splitPath(path);

		return array.length === 1 ?
			(root[path] = obj) :
			objTo(root, array, obj);
	}

	Sparky.get = getPath;
	Sparky.set = setPath;
	Sparky.observePath = observePath;
	Sparky.unobservePath = unobservePath;
	Sparky.observePathOnce = observePathOnce;

	// Binding

	function isAudioParam(object) {
		return window.AudioParam && window.AudioParam.prototype.isPrototypeOf(object);
	}

	function Poll(object, property, fn) {
		var v1 = object[property];
		var active = true;

		function frame() {
			var v2 = object[property];

			if (v1 !== v2) {
				v1 = v2;
				fn();
			}

			if (!active) { return; }

			window.requestAnimationFrame(frame);
		};

		function cancel() {
			active = false;
		}

		window.requestAnimationFrame(frame);
		return cancel;
	}

	var unpollers = [];

	function poll(object, property, fn) {
		unpollers.push([object, property, fn, Poll(object, property, fn)]);
		return object;
	}

	function unpoll(object, property, fn) {
		var n = unpollers.length;
		var unpoller;

		while (n--) {
			unpoller = unpollers[n];

			if (object === unpoller[0] && property === unpoller[1] && fn === unpoller[2]) {
				unpoller[3]();
				unpollers.splice(n, 1);
				return object;
			}
		}

		return object;
	}

	(false && Object.observe && window.WeakMap ? function(Sparky) {
		if (Sparky.debug) { console.log('Sparky: Ooo. Lucky you, using Object.observe and WeakMap.'); }

		var map = new WeakMap();
		var names = [];
		var types = ["add", "update", "delete"];

		function call(fn) {
			fn(this);
		}

		function trigger(change) {
			var properties = this;
			var name = change.name;
			var object = change.object;

			// If this property is in the properties being watched, and we
			// have not already called changes on it, do that now.
			if (properties[name] && names.indexOf(name) === -1) {
				names.push(name);
				fns = properties[name];
				fns.forEach(call, object);
			}
		}

		function triggerAll(changes) {
			names.length = 0;
			changes.forEach(trigger, map[object]);
		}

		function setup(object) {
			var properties = map[object] = {};
			Object.observe(object, triggerAll, types);
			return properties;
		}

		function teardown(object) {
			Object.unobserve(object, triggerAll);
		}

		Sparky.observe = function(object, property, fn) {
			var properties = map[object] || setup(object);
			var fns = properties[property] || (properties[property] = []);
			fns.push(fn);
		};

		Sparky.unobserve = function(object, property, fn) {
			if (!map[object]) { return; }

			var properties = map[object];
			var fns = properties[property];

			if (!fns) { return; }

			var n = fns.length;

			while (n--) { fns.splice(n, 1); }

			if (fns.length === 0) {
				delete properties[property];

				if (Object.keys[properties].length === 0) {
					teardown(object);
				}
			}
		};
	} : function(Sparky) {
		Sparky.observe = function(object, property, fn, immediate) {
			if (!object) {
				throw new Error('Sparky: Sparky.observe requires an object!', object, property);
			}

			// AudioParams objects must be polled, as they cannot be reconfigured
			// to getters/setters, nor can they be Object.observed. And they fail
			// to do both of those completely silently. So we test the scope to see
			// if it is an AudioParam and set the observe and unobserve functions
			// to poll.
			if (isAudioParam(object)) {
				return poll(object, property, fn);
			}

			if (property === 'length') {
				// Observe length and update the DOM on next
				// animation frame if it changes.
				var descriptor = Object.getOwnPropertyDescriptor(object, property);

				if (!descriptor.get && !descriptor.configurable) {
					console.warn && console.warn('Sparky: Are you trying to observe an array?. Sparky is going to observe it by polling. You may want to use a Collection() to avoid this.', object, object instanceof Array);
					console.trace && console.trace();
					return poll(object, property, fn);
				}
			}

			observe(object, property, fn);
			if (immediate) { fn(object); }
		};

		Sparky.unobserve = function(object, property, fn) {
			if (isAudioParam(object)) {
				return unpoll(object, property, fn);
			}

			if (property === 'length') {
				var descriptor = Object.getOwnPropertyDescriptor(object, property);
				if (!descriptor.get && !descriptor.configurable) {
					return unpoll(object, property, fn);
				}
			}

			return unobserve(object, property, fn);
		};
	})(Sparky)
})(Sparky);
<|endoftext|>


<commit_before>/*
* BrainBrowser: Web-based Neurological Visualization Tools
* (https://brainbrowser.cbrain.mcgill.ca)
*
* Copyright (C) 2011 McGill University
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

"use strict";

var fs = require("fs");
var pkg = require("../package.json");
var info = require("../canarie-rpi/info.json");

info.version = "BrainBrowser v" + pkg.version + ", Web Service v" + pkg.webServiceVersion;

exports.info = function(req, res) {

  res.format({
    html: function(){
      res.render("canarie/info", { info: info });
    },

    json: function(){
      res.send(info);
    }
  });

};

exports.stats = function(req, res) {
  fs.readFile("canarie-rpi/stats.json", { encoding: "utf8" }, function(err, data) {
    var stats;

    if (err) {
      stats = {
        invocations: 0,
        lastReset: new Date().toISOString()
      };
    } else {
      stats = JSON.parse(data);
    }

    res.send(stats);
  });
};

exports.doc = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#web-service");
};

exports.releasenotes = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#web-service");
};

exports.support = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#credits");
};

exports.source = function(req, res) {
  res.status(204).send("Not available.");
};

exports.tryme = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/surface-viewer");
};

exports.license = function(req, res) {
  fs.readFile("LICENSE", { encoding: "utf8" }, function(err, data) {
    res.type("text/plain").send(data);
  });
};

<commit_msg>Fixed JSON responses for RPI.<commit_after>/*
* BrainBrowser: Web-based Neurological Visualization Tools
* (https://brainbrowser.cbrain.mcgill.ca)
*
* Copyright (C) 2011 McGill University
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

"use strict";

var fs = require("fs");
var pkg = require("../package.json");
var info = require("../canarie-rpi/info.json");

info.version = "BrainBrowser v" + pkg.version + ", Web Service v" + pkg.webServiceVersion;

exports.info = function(req, res) {

  res.format({
    html: function(){
      res.render("canarie/info", { info: info });
    },

    json: function(){
      res.type("application/json").send(JSON.stringify(info, null, 2));
    }
  });

};

exports.stats = function(req, res) {
  fs.readFile("canarie-rpi/stats.json", { encoding: "utf8" }, function(err, data) {
    var stats;

    if (err) {
      stats = {
        invocations: 0,
        lastReset: new Date().toISOString()
      };
    } else {
      stats = JSON.parse(data);
    }
    res.type("application/json").send(JSON.stringify(stats, null, 2));
  });
};

exports.doc = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#web-service");
};

exports.releasenotes = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#web-service");
};

exports.support = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/#credits");
};

exports.source = function(req, res) {
  res.status(204).send("Not available.");
};

exports.tryme = function(req, res) {
  res.redirect("https://brainbrowser.cbrain.mcgill.ca/surface-viewer");
};

exports.license = function(req, res) {
  fs.readFile("LICENSE", { encoding: "utf8" }, function(err, data) {
    res.type("text/plain").send(data);
  });
};

<|endoftext|>


<commit_before>"use strict";
/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2013, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */

(function() {

  window.OSjs   = window.OSjs   || {};
  OSjs.Handlers = OSjs.Handlers || {};

  /////////////////////////////////////////////////////////////////////////////
  // DEFAULT HANDLING CODE
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Storage
   */
  var DefaultStorage = function() {
    if ( !OSjs.Utils.getCompability().localStorage ) {
      throw "Your browser does not support localStorage :(";
    }
    this.prefix = 'andersevenrud.github.io/OS.js-v2/';
  };

  DefaultStorage.prototype.set = function(k, v) {
    localStorage.setItem(this.prefix + k, JSON.stringify(v));
  };

  DefaultStorage.prototype.get = function(k) {
    var val = localStorage.getItem(this.prefix + k);
    return val ? JSON.parse(val) : null;
  };

  /**
   * Handler
   */
  var DefaultHandler = function() {
    this.storage  = new DefaultStorage();
    this.packages = {};
    this.config   = OSjs.Settings.DefaultConfig();
    this.userData = {};
  };

  DefaultHandler.prototype.call = function(opts, cok, cerror) {
    return OSjs.Utils.Ajax(this.config.Core.APIURI, function(response, httpRequest, url) {
      cok.apply(this, arguments);
    }, function(error, response, httpRequest, url) {
      cerror.apply(this, arguments);
    }, opts);
  };

  DefaultHandler.prototype.init = function(callback) {
    var self      = this;
    var container = document.getElementById('Login');
    var login     = document.getElementById('LoginForm');
    var u         = document.getElementById('LoginUsername');
    var p         = document.getElementById('LoginPassword');
    var s         = document.getElementById('LoginSubmit');

    var _restore = function() {
      s.removeAttribute("disabled");
      u.removeAttribute("disabled");
      p.removeAttribute("disabled");
    };

    var _lock = function() {
      s.setAttribute("disabled", "disabled");
      u.setAttribute("disabled", "disabled");
      p.setAttribute("disabled", "disabled");
    };

    var _login = function(username, password) {
      self.login(username, password, function(result, error) {
        if ( error ) {
          alert(error);
          _restore();
          return;
        }
        self.userData = result;

        container.parentNode.removeChild(container);
        callback();
      });
    };

    /*
    login.onsubmit = function(ev) {
      _lock();
      if ( ev ) ev.preventDefault();
      _login(u.value, p.value);
    };
    */

    _login("demo", "demo");
  };

  DefaultHandler.prototype.boot = function(callback) {
    callback = callback || {};
    var self = this;

    this.pollPackages(function(result, error) {
      if ( error ) {
        callback(false, error);
        return;
      }

      if ( result ) {
        self.packages = result;
        callback(true);
        return;
      }

      callback(false);
    });
  };

  DefaultHandler.prototype.login = function(username, password, callback) {
    if ( username === 'demo' && password === 'demo' ) {
      var userData = {
        id:         1,
        username:   'demo',
        name:       'Demo User',
        groups:     ['demo']
      };

      callback(userData);
      return;
    }
    callback(false, "Invalid login");
  };

  DefaultHandler.prototype.logout = function(session, callback) {
    if ( session !== null ) {
      this.setUserSession(session, function() {
        callback(true);
      });
      return;
    }
    callback(true);
  };

  DefaultHandler.prototype.loadSession = function() {
    var _list = [];

    var onSuccess = function(data, a) {
      var w, r;
      for ( var i = 0, l = data.length; i < l; i++ ) {
        r = data[i];
        w = a._getWindow(r.name);
        if ( w ) {
          w._move(r.position.x, r.position.y);
          w._resize(r.dimension.w, r.dimension.h);

          console.info('DefaultHandler::loadSession()->onSuccess()', 'Restored window "' + r.name + '" from session');
        }
      }

      onNext();
    };

    var onNext = function() {
      if ( _list.length ) {
        var s = _list.pop();
        var sargs = s.args || {};
        if ( typeof sargs.length !== 'undefined' ) sargs = {};

        OSjs.API.launch(s.name, sargs, (function(data) {
          return function(a) {
            onSuccess(data, a);
          };
        })(s.windows), function(err) {
          console.warn("_loadSession() error", err);
          onNext();
        });
      }
    };

    this.getUserSession(function(res) {
      if ( res ) {
        _list = res;
        onNext();
      }
    });
  };

  DefaultHandler.prototype.pollPackages = function(callback) {
    callback = callback || function() {};

    var uri = this.getConfig('Core').PACKAGEURI;
    return OSjs.Utils.Ajax(uri, function(response, httpRequest, url) {
      if ( response ) {
        callback(response);
      } else {
        callback(false, "No packages found!");
      }
    }, function(error) {
      callback(false, error);
    }, {method: 'GET', parse: true});
  };

  DefaultHandler.prototype.getApplicationsMetadata = function() {
    return this.packages;
  };

  DefaultHandler.prototype.getApplicationNameByMime = function(mime, fname) {
    var j, i, a;
    var list = [];
    for ( i in this.packages ) {
      if ( this.packages.hasOwnProperty(i) ) {
        a = this.packages[i];
        if ( a && a.mime ) {
          for ( j = 0; j < a.mime.length; j++ ) {
            if ( (new RegExp(a.mime[j])).test(mime) === true ) {
              list.push(i);
            }
          }
        }
      }
    }

    return list;
  };

  DefaultHandler.prototype.getApplicationMetadata = function(name) {
    if ( this.packages[name] ) {
      return this.packages[name];
    }
    return false;
  };

  DefaultHandler.prototype.setUserSettings = function(key, opts, callback) {
    callback = callback || function() {};
    var settings = this.storage.get("userSettings");
    if ( typeof settings !== 'object' ) {
      settings = {};
    }
    settings[key] = opts;

    this.storage.set("userSettings", settings);
    callback(true);
  };

  DefaultHandler.prototype.getUserSettings = function(key, callback) {
    callback = callback || function() {};
    var s = this.storage.get("userSettings") || {};
    if ( s[key] ) {
      callback(s[key]);
      return;
    }
    callback(false);
  };

  DefaultHandler.prototype.setUserSession = function(session, callback) {
    callback = callback || function() {};
    this.storage.set("userSession", session);
    callback(true);
  };

  DefaultHandler.prototype.getUserSession = function(callback) {
    callback = callback || function() {};
    var s = this.storage.get("userSession");
    callback(s);
  };

  DefaultHandler.prototype.getConfig = function(key) {
    return key ? this.config[key] : this.config;
  };

  DefaultHandler.prototype.getUserData = function() {
    return this.userData;
  };

  DefaultHandler.prototype.getThemeResource = function(name, type, args) {
    type = type || null;
    args = args || null;

    var wm = OSjs.API.getWMInstance();
    var theme = (wm ? wm.getSetting('theme') : 'default') || 'default';
    if ( !name.match(/^\//) ) {
      if ( type == 'icon' ) {
        var size = args || '16x16';
        name = '/themes/' + theme + '/icons/' + size + '/' + name;
      } else if ( type == 'sound' ) {
        var ext = 'oga';
        if ( !OSjs.Utils.getCompability().audioTypes.ogg ) {
          ext = 'mp3';
        }
        name = '/themes/' + theme + '/sounds/' + name + '.' + ext;
      } else if ( type == 'wm' ) {
        name = '/themes/' + theme + '/wm/' + name;
      } else if ( type == 'base' ) {
        name = '/themes/' + theme + '/' + name;
      }
    }

    return name;
  };

  DefaultHandler.prototype.getThemeCSS = function(name) {
    if ( name === null ) {
      return '/frontend/blank.css';
    }
    return '/themes/' + name + '.css';
  }

  DefaultHandler.prototype.getResourceURL = function(path) {
    if ( path && path.match(/^\/(themes|frontend|apps)/) ) {
      return path;
    }
    var fsuri = this.getConfig('Core').FSURI;
    return path ? (fsuri + path) : fsuri;
  }

  OSjs.Handlers.Default = DefaultHandler;

})();

<commit_msg>Bugfix for removing old settings<commit_after>"use strict";
/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2013, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */

(function() {

  window.OSjs   = window.OSjs   || {};
  OSjs.Handlers = OSjs.Handlers || {};

  /////////////////////////////////////////////////////////////////////////////
  // DEFAULT HANDLING CODE
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Storage
   */
  var DefaultStorage = function() {
    if ( !OSjs.Utils.getCompability().localStorage ) {
      throw "Your browser does not support localStorage :(";
    }
    this.prefix = 'andersevenrud.github.io/OS.js-v2/';
  };

  DefaultStorage.prototype.set = function(k, v) {
    localStorage.setItem(this.prefix + k, JSON.stringify(v));
  };

  DefaultStorage.prototype.get = function(k) {
    var val = localStorage.getItem(this.prefix + k);
    return val ? JSON.parse(val) : null;
  };

  /**
   * Handler
   */
  var DefaultHandler = function() {
    this.storage  = new DefaultStorage();
    this.packages = {};
    this.config   = OSjs.Settings.DefaultConfig();
    this.userData = {};
  };

  DefaultHandler.prototype.call = function(opts, cok, cerror) {
    return OSjs.Utils.Ajax(this.config.Core.APIURI, function(response, httpRequest, url) {
      cok.apply(this, arguments);
    }, function(error, response, httpRequest, url) {
      cerror.apply(this, arguments);
    }, opts);
  };

  DefaultHandler.prototype.init = function(callback) {
    var self      = this;
    var container = document.getElementById('Login');
    var login     = document.getElementById('LoginForm');
    var u         = document.getElementById('LoginUsername');
    var p         = document.getElementById('LoginPassword');
    var s         = document.getElementById('LoginSubmit');

    var _restore = function() {
      s.removeAttribute("disabled");
      u.removeAttribute("disabled");
      p.removeAttribute("disabled");
    };

    var _lock = function() {
      s.setAttribute("disabled", "disabled");
      u.setAttribute("disabled", "disabled");
      p.setAttribute("disabled", "disabled");
    };

    var _login = function(username, password) {
      self.login(username, password, function(result, error) {
        if ( error ) {
          alert(error);
          _restore();
          return;
        }
        self.userData = result;

        container.parentNode.removeChild(container);
        callback();
      });
    };

    /*
    login.onsubmit = function(ev) {
      _lock();
      if ( ev ) ev.preventDefault();
      _login(u.value, p.value);
    };
    */

    _login("demo", "demo");
  };

  DefaultHandler.prototype.boot = function(callback) {
    callback = callback || {};
    var self = this;

    this.pollPackages(function(result, error) {
      if ( error ) {
        callback(false, error);
        return;
      }

      if ( result ) {
        self.packages = result;
        callback(true);
        return;
      }

      callback(false);
    });
  };

  DefaultHandler.prototype.login = function(username, password, callback) {
    if ( username === 'demo' && password === 'demo' ) {
      var userData = {
        id:         1,
        username:   'demo',
        name:       'Demo User',
        groups:     ['demo']
      };

      callback(userData);
      return;
    }
    callback(false, "Invalid login");
  };

  DefaultHandler.prototype.logout = function(session, callback) {
    if ( session !== null ) {
      this.setUserSession(session, function() {
        callback(true);
      });
      return;
    }
    callback(true);
  };

  DefaultHandler.prototype.loadSession = function() {
    var _list = [];

    var onSuccess = function(data, a) {
      var w, r;
      for ( var i = 0, l = data.length; i < l; i++ ) {
        r = data[i];
        w = a._getWindow(r.name);
        if ( w ) {
          w._move(r.position.x, r.position.y);
          w._resize(r.dimension.w, r.dimension.h);

          console.info('DefaultHandler::loadSession()->onSuccess()', 'Restored window "' + r.name + '" from session');
        }
      }

      onNext();
    };

    var onNext = function() {
      if ( _list.length ) {
        var s = _list.pop();
        var sargs = s.args || {};
        if ( typeof sargs.length !== 'undefined' ) sargs = {};

        OSjs.API.launch(s.name, sargs, (function(data) {
          return function(a) {
            onSuccess(data, a);
          };
        })(s.windows), function(err) {
          console.warn("_loadSession() error", err);
          onNext();
        });
      }
    };

    this.getUserSession(function(res) {
      if ( res ) {
        _list = res;
        onNext();
      }
    });
  };

  DefaultHandler.prototype.pollPackages = function(callback) {
    callback = callback || function() {};

    var uri = this.getConfig('Core').PACKAGEURI;
    return OSjs.Utils.Ajax(uri, function(response, httpRequest, url) {
      if ( response ) {
        callback(response);
      } else {
        callback(false, "No packages found!");
      }
    }, function(error) {
      callback(false, error);
    }, {method: 'GET', parse: true});
  };

  DefaultHandler.prototype.getApplicationsMetadata = function() {
    return this.packages;
  };

  DefaultHandler.prototype.getApplicationNameByMime = function(mime, fname) {
    var j, i, a;
    var list = [];
    for ( i in this.packages ) {
      if ( this.packages.hasOwnProperty(i) ) {
        a = this.packages[i];
        if ( a && a.mime ) {
          for ( j = 0; j < a.mime.length; j++ ) {
            if ( (new RegExp(a.mime[j])).test(mime) === true ) {
              list.push(i);
            }
          }
        }
      }
    }

    return list;
  };

  DefaultHandler.prototype.getApplicationMetadata = function(name) {
    if ( this.packages[name] ) {
      return this.packages[name];
    }
    return false;
  };

  DefaultHandler.prototype.setUserSettings = function(key, opts, callback) {
    callback = callback || function() {};
    var settings = this.storage.get("userSettings");
    if ( typeof settings !== 'object' ) {
      settings = {};
    }
    if ( !settings[key] || typeof settings[key] !== 'object' ) {
      settings[key] = {};
    }
    settings[key] = opts;

    this.storage.set("userSettings", settings);
    callback(true);
  };

  DefaultHandler.prototype.getUserSettings = function(key, callback) {
    callback = callback || function() {};
    var s = this.storage.get("userSettings") || {};
    if ( s[key] ) {
      callback(s[key]);
      return;
    }
    callback(false);
  };

  DefaultHandler.prototype.setUserSession = function(session, callback) {
    callback = callback || function() {};
    this.storage.set("userSession", session);
    callback(true);
  };

  DefaultHandler.prototype.getUserSession = function(callback) {
    callback = callback || function() {};
    var s = this.storage.get("userSession");
    callback(s);
  };

  DefaultHandler.prototype.getConfig = function(key) {
    return key ? this.config[key] : this.config;
  };

  DefaultHandler.prototype.getUserData = function() {
    return this.userData;
  };

  DefaultHandler.prototype.getThemeResource = function(name, type, args) {
    type = type || null;
    args = args || null;

    var wm = OSjs.API.getWMInstance();
    var theme = (wm ? wm.getSetting('theme') : 'default') || 'default';
    if ( !name.match(/^\//) ) {
      if ( type == 'icon' ) {
        var size = args || '16x16';
        name = '/themes/' + theme + '/icons/' + size + '/' + name;
      } else if ( type == 'sound' ) {
        var ext = 'oga';
        if ( !OSjs.Utils.getCompability().audioTypes.ogg ) {
          ext = 'mp3';
        }
        name = '/themes/' + theme + '/sounds/' + name + '.' + ext;
      } else if ( type == 'wm' ) {
        name = '/themes/' + theme + '/wm/' + name;
      } else if ( type == 'base' ) {
        name = '/themes/' + theme + '/' + name;
      }
    }

    return name;
  };

  DefaultHandler.prototype.getThemeCSS = function(name) {
    if ( name === null ) {
      return '/frontend/blank.css';
    }
    return '/themes/' + name + '.css';
  }

  DefaultHandler.prototype.getResourceURL = function(path) {
    if ( path && path.match(/^\/(themes|frontend|apps)/) ) {
      return path;
    }
    var fsuri = this.getConfig('Core').FSURI;
    return path ? (fsuri + path) : fsuri;
  }

  OSjs.Handlers.Default = DefaultHandler;

})();

<|endoftext|>


<commit_before>$(document).ready(function() {
  if ('undefined' == typeof page) { page = {}; window.page = page; }
  page.draggable = function () {
    Draggable.create(".box", {type:"x,y", edgeResistance:0.65, bounds:"#container", throwProps:true});
  };
  page.slideshow = {};
  page.slideshow.timeline = new TimelineMax({repeat:-1});
  page.slideshow.load = function () {
    page.slideshow.timeline.append(
      TweenLite
    );
  };
  page.slideshow.advance = function () {
    var $slides = $(".slide");
    var currentSlide = 0;
    var stayTime = 3;
    var slideTime = 1.3;
    TweenLite.set($slides.filter(":gt(0)"), {autoAlpha:0});
    TweenLite.delayedCall(stayTime, nextSlide);

    function nextSlide(){
      TweenLite.to( $slides.eq(currentSlide), slideTime, {autoAlpha:0} );
      currentSlide = ++currentSlide % $slides.length;
      TweenLite.to( $slides.eq(currentSlide), slideTime, {autoAlpha:1} );
      TweenLite.delayedCall(stayTime, nextSlide);
    }
  };
  page.slideshow.get_current_slide = function () {};
  page.slideshow.get_next_slide = function () {};

  // now run it
  page.draggable();
});
<commit_msg>Add js code for draggable demo<commit_after>/*
See http://www.greensock.com/draggable/ for details.
This demo uses ThrowPropsPlugin which is a membership benefit of Club GreenSock, http://www.greensock.com/club/
*/

var $snap = $("#snap"),
  $liveSnap = $("#liveSnap"),
	$container = $("#container"),
	gridWidth = 196,
	gridHeight = 100,
	gridRows = 6,
	gridColumns = 5,
	i, x, y;

//loop through and create the grid (a div for each cell). Feel free to tweak the variables above
for (i = 0; i < gridRows * gridColumns; i++) {
	y = Math.floor(i / gridColumns) * gridHeight;
	x = (i * gridWidth) % (gridColumns * gridWidth);
	$("<div/>").css({position:"absolute", border:"1px solid #454545", width:gridWidth-1, height:gridHeight-1, top:y, left:x}).prependTo($container);
}

//set the container's size to match the grid, and ensure that the box widths/heights reflect the variables above
TweenLite.set($container, {height: gridRows * gridHeight + 1, width: gridColumns * gridWidth + 1});
TweenLite.set(".box", {width:gridWidth, height:gridHeight, lineHeight:gridHeight + "px"});

//the update() function is what creates the Draggable according to the options selected (snapping).
function update() {
  var snap = $snap.prop("checked"),
      liveSnap = $liveSnap.prop("checked");
	Draggable.create(".box", {
		bounds:$container,
		edgeResistance:0.65,
		type:"x,y",
		throwProps:true,
		liveSnap:liveSnap,
		snap:{
			x: function(endValue) {
				return (snap || liveSnap) ? Math.round(endValue / gridWidth) * gridWidth : endValue;
			},
			y: function(endValue) {
				return (snap || liveSnap) ? Math.round(endValue / gridHeight) * gridHeight : endValue;
			}
		}
	});
}

//when the user toggles one of the "snap" modes, make the necessary updates...
$snap.on("change", applySnap);
$liveSnap.on("change", applySnap);

function applySnap() {
	if ($snap.prop("checked") || $liveSnap.prop("checked")) {
		$(".box").each(function(index, element) {
			TweenLite.to(element, 0.5, {
				x:Math.round(element._gsTransform.x / gridWidth) * gridWidth,
				y:Math.round(element._gsTransform.y / gridHeight) * gridHeight,
				delay:0.1,
				ease:Power2.easeInOut
			});
		});
	}
	update();
}

update();
<|endoftext|>


<commit_before>/* eslint-disable no-restricted-globals */
/* global __STORYBOOK_CLIENT_API__ */

/**
 * External dependencies
 */
import lodash from 'lodash';
import React from 'react';
import { addDecorator, configure } from '@storybook/react';

/**
 * WordPress dependencies
 */
import { createHigherOrderComponent } from '@wordpress/compose';
import {
	Component,
	createRef,
	Fragment,
	createElement,
	createPortal,
} from '@wordpress/element';
import { __, sprintf, setLocaleData } from '@wordpress/i18n';
import {
	getQueryString,
	addQueryArgs,
} from '@wordpress/url';
import {
	addFilter,
	removeFilter,
	addAction,
	doAction,
	applyFilters,
	removeAction,
	removeAllFilters,
} from '@wordpress/hooks';

/**
 * Internal dependencies
 */
import '../assets/sass/wpdashboard.scss';
import '../assets/sass/adminbar.scss';
import '../assets/sass/admin.scss';
import './assets/sass/wp-admin.scss';
import { googlesitekit as dashboardData } from '../.storybook/data/wp-admin-admin.php-page=googlesitekit-dashboard-googlesitekit';
import { bootstrapFetchMocks } from './fetch-mocks';
import { disableFeature } from '../stories/utils/features';

// Setup.
const wp = {};
wp.element = wp.element || {};
wp.i18n = wp.i18n || {};
wp.hooks = wp.hooks || {};
wp.url = {
	getQueryString,
	addQueryArgs,
};
wp.compose = {};
wp.compose.createHigherOrderComponent = createHigherOrderComponent;
wp.hooks.addFilter = addFilter;
wp.hooks.removeFilter = removeFilter;
wp.hooks.addAction = addAction;
wp.hooks.doAction = doAction;
wp.hooks.applyFilters = applyFilters;
wp.hooks.removeAction = removeAction;
wp.hooks.removeAllFilters = removeAllFilters;
wp.element.Component = Component;
wp.element.createRef = createRef;
wp.element.Fragment = Fragment;
wp.element.createElement = createElement;
wp.element.createPortal = createPortal;
wp.i18n.__ = __ || {};
wp.i18n.setLocaleData = setLocaleData || {};
wp.i18n.sprintf = sprintf || {};
global.wp = global.wp || wp;
global.React = React;
global.lodash = lodash;
global._googlesitekitLegacyData = dashboardData;
global._googlesitekitLegacyData.admin.assetsRoot = './assets/';
global._googlesitekitLegacyData.isStorybook = true;
global._googlesitekitBaseData = {
	homeURL: 'http://example.com/',
	referenceSiteURL: 'http://example.com/',
	userIDHash: 'storybook',
	adminURL: 'http://example.com/wp-admin/',
	assetsURL: 'http://example.com/wp-content/plugins/google-site-kit/dist/assets/',
	blogPrefix: 'wp_',
	ampMode: false,
	isNetworkMode: false,
	isFirstAdmin: true,
	isOwner: true,
	splashURL: 'http://example.com/wp-admin/admin.php?page=googlesitekit-splash',
	proxySetupURL: 'https://sitekit.withgoogle.com/site-management/setup/?scope=openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsiteverification%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fwebmasters%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.manage.users%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.edit&supports=credentials_retrieval%20short_verification_token%20file_verification&nonce=&site_id=storybooksiteid.apps.sitekit.withgoogle.com',
	proxyPermissionsURL: 'https://sitekit.withgoogle.com/site-management/permissions/?token=storybooktoken&site_id=storybooksiteid.apps.sitekit.withgoogle.com',
	trackingEnabled: false,
	trackingID: 'UA-000000000-1',
};
global._googlesitekitEntityData = {
	currentEntityURL: null,
	currentEntityType: null,
	currentEntityTitle: null,
	currentEntityID: null,
};

bootstrapFetchMocks();

global.resetFeatures = () => {
	disableFeature( 'widgets.dashboard' );
	disableFeature( 'widgets.pageDashboard' );
	disableFeature( 'userInput' );
	disableFeature( 'storeErrorNotifications' );
	disableFeature( 'serviceSetupV2' );
};
addDecorator( ( story ) => {
	// Disable all features before each story.
	global.resetFeatures();
	return story();
} );

// Global Decorator.
addDecorator( ( story ) => (

{ story() }

) );

const req = require.context( '../stories', true, /\.stories\.js$/ );

function loadStories() {
	req.keys().forEach( ( filename ) => req( filename ) );
}

configure( loadStories, module );

// TODO Would be nice if this wrote to a file. This logs our Storybook data to the browser console. Currently it gets put in .storybook/storybook-data and used in tests/backstop/scenarios.js.
// eslint-disable-next-line no-console
console.log( '__STORYBOOK_CLIENT_API__.raw()', __STORYBOOK_CLIENT_API__.raw() );
<commit_msg>Reset globals for every story and remove unnecessary setup from Storybook config.<commit_after>/**
 * Storybook config.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import cloneDeep from 'lodash/cloneDeep';
import { addDecorator, configure } from '@storybook/react';

/**
 * Internal dependencies
 */
import '../assets/sass/wpdashboard.scss';
import '../assets/sass/adminbar.scss';
import '../assets/sass/admin.scss';
import './assets/sass/wp-admin.scss';
import { bootstrapFetchMocks } from './fetch-mocks';
import { disableFeature } from '../stories/utils/features';
// TODO: Remove when legacy data API is removed.
import { googlesitekit as dashboardData } from '../.storybook/data/wp-admin-admin.php-page=googlesitekit-dashboard-googlesitekit';

bootstrapFetchMocks();

const resetFeatures = () => {
	disableFeature( 'widgets.dashboard' );
	disableFeature( 'widgets.pageDashboard' );
	disableFeature( 'userInput' );
	disableFeature( 'storeErrorNotifications' );
	disableFeature( 'serviceSetupV2' );
};
const resetGlobals = () => {
	global._googlesitekitLegacyData = cloneDeep( dashboardData );
	global._googlesitekitLegacyData.admin.assetsRoot = './assets/';
	global._googlesitekitLegacyData.isStorybook = true;
	global._googlesitekitBaseData = {
		homeURL: 'http://example.com/',
		referenceSiteURL: 'http://example.com/',
		userIDHash: 'storybook',
		adminURL: 'http://example.com/wp-admin/',
		assetsURL: 'http://example.com/wp-content/plugins/google-site-kit/dist/assets/',
		blogPrefix: 'wp_',
		ampMode: false,
		isNetworkMode: false,
		isFirstAdmin: true,
		isOwner: true,
		splashURL: 'http://example.com/wp-admin/admin.php?page=googlesitekit-splash',
		proxySetupURL: 'https://sitekit.withgoogle.com/site-management/setup/?scope=openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsiteverification%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fwebmasters%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.manage.users%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.edit&supports=credentials_retrieval%20short_verification_token%20file_verification&nonce=&site_id=storybooksiteid.apps.sitekit.withgoogle.com',
		proxyPermissionsURL: 'https://sitekit.withgoogle.com/site-management/permissions/?token=storybooktoken&site_id=storybooksiteid.apps.sitekit.withgoogle.com',
		trackingEnabled: false,
		trackingID: 'UA-000000000-1',
	};
	global._googlesitekitEntityData = {
		currentEntityURL: null,
		currentEntityType: null,
		currentEntityTitle: null,
		currentEntityID: null,
	};
};
resetGlobals();

addDecorator( ( story ) => {
	resetGlobals();
	resetFeatures();
	return story();
} );

// Global Decorator.
addDecorator( ( story ) => (

{ story() }

) );

const req = require.context( '../stories', true, /\.stories\.js$/ );

function loadStories() {
	req.keys().forEach( ( filename ) => req( filename ) );
}

configure( loadStories, module );

// TODO Would be nice if this wrote to a file. This logs our Storybook data to the browser console. Currently it gets put in .storybook/storybook-data and used in tests/backstop/scenarios.js.
// eslint-disable-next-line no-console
console.log( '__STORYBOOK_CLIENT_API__.raw()', global.__STORYBOOK_CLIENT_API__.raw() );
<|endoftext|>