<commit_before>'use strict';

define(['angular', 'ol', 'sidebar', 'toolbar', 'layermanager', 'map', 'query', 'search', 'print', 'permalink', 'measure', 'legend', 'geolocation', 'core', 'api', 'angular-gettext', 'bootstrap', 'translations', 'compositions', 'status_creator', 'ows'],

    function(angular, ol, toolbar, layermanager) {
        var module = angular.module('hs', [
            'hs.toolbar',
            'hs.layermanager',
            'hs.map',
            'hs.query',
            'hs.search', 'hs.print', 'hs.permalink', 'hs.measure',
            'hs.legend', 'hs.geolocation', 'hs.core',
            'hs.api',
            'hs.ows',
            'gettext',
            'hs.compositions', 'hs.status_creator',
            'hs.sidebar'
        ]);

        module.directive('hs', ['hs.map.service', 'Core', function(OlMap, Core) {
            return {
                templateUrl: hsl_path + 'hslayers.html',
                link: function(scope, element) {
                    Core.fullScreenMap(element);
                }
            };
        }]);

        var caturl = "/php/metadata/csw/index.php";

        module.value('config', {
            design: 'md',
            default_layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM({
                        wrapX: false
                    }),
                    title: "Base layer",
                    base: true
                })
            ],
            //project_name: 'hslayers',
            project_name: 'Material',
            default_view: new ol.View({
                center: ol.proj.transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
                zoom: 5,
                units: "m"
            }),
            hostname: {
                "default": {
                    "title": "Default",
                    "type": "default",
                    "editable": false,
                    "url": 'http://atlas.kraj-lbc.cz'
                }/*,
                "compositions_catalogue": {
                    "title": "Compositions catalogue",
                    "type": "compositions_catalogue",
                    "editable": true,
                    "url": 'http://foodie-dev.wirelessinfo.cz'
                },*/
                "status_manager": {
                    "title": "Status manager",
                    "type": "status_manager",
                    "editable": true,
                    "url": 'http://foodie-dev.wirelessinfo.cz'
                }
            },
            social_hashtag: 'via @opentnet',
            //compositions_catalogue_url: '/p4b-dev/cat/catalogue/libs/cswclient/cswClientRun.php',
            //compositions_catalogue_url: 'http://erra.ccss.cz/php/metadata/csw/index.php',
            //status_manager_url: '/wwwlibs/statusmanager2/index.php',

           'catalogue_url': caturl || '/php/metadata/csw/',
           'compositions_catalogue_url': caturl || '/php/metadata/csw/',
           status_manager_url: '/wwwlibs/statusmanager/index.php',

            createExtraMenu: function($compile, $scope, element) {
                $scope.uploadClicked = function() {
                    alert("UPLOAD!")
                }
                var el = angular.element("
Upload
");
                element.find('ul').append(el);
                $compile(el)($scope);
            }
        });

        module.controller('Main', ['$scope', 'Core', 'hs.query.baseService', 'hs.compositions.service_parser',
            function($scope, Core, QueryService, composition_parser) {
                if (console) console.log("Main called");
                $scope.hsl_path = hsl_path; //Get this from hslayers.js file
                $scope.Core = Core;
                Core.setMainPanel('composition_browser');
                //composition_parser.load('http://www.whatstheplan.eu/wwwlibs/statusmanager2/index.php?request=load&id=972cd7d1-e057-417b-96a7-e6bf85472b1e');
                $scope.$on('query.dataUpdated', function(event) {
                    if (console) console.log('Attributes', QueryService.data.attributes, 'Groups', QueryService.data.groups);
                });
            }
        ]);

        return module;
    });
<commit_msg>Missing comma<commit_after>'use strict';

define(['angular', 'ol', 'sidebar', 'toolbar', 'layermanager', 'map', 'query', 'search', 'print', 'permalink', 'measure', 'legend', 'geolocation', 'core', 'api', 'angular-gettext', 'bootstrap', 'translations', 'compositions', 'status_creator', 'ows'],

    function(angular, ol, toolbar, layermanager) {
        var module = angular.module('hs', [
            'hs.toolbar',
            'hs.layermanager',
            'hs.map',
            'hs.query',
            'hs.search', 'hs.print', 'hs.permalink', 'hs.measure',
            'hs.legend', 'hs.geolocation', 'hs.core',
            'hs.api',
            'hs.ows',
            'gettext',
            'hs.compositions', 'hs.status_creator',
            'hs.sidebar'
        ]);

        module.directive('hs', ['hs.map.service', 'Core', function(OlMap, Core) {
            return {
                templateUrl: hsl_path + 'hslayers.html',
                link: function(scope, element) {
                    Core.fullScreenMap(element);
                }
            };
        }]);

        var caturl = "/php/metadata/csw/index.php";

        module.value('config', {
            design: 'md',
            default_layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM({
                        wrapX: false
                    }),
                    title: "Base layer",
                    base: true
                })
            ],
            //project_name: 'hslayers',
            project_name: 'Material',
            default_view: new ol.View({
                center: ol.proj.transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
                zoom: 5,
                units: "m"
            }),
            hostname: {
                "default": {
                    "title": "Default",
                    "type": "default",
                    "editable": false,
                    "url": 'http://atlas.kraj-lbc.cz'
                }, /*,
                "compositions_catalogue": {
                    "title": "Compositions catalogue",
                    "type": "compositions_catalogue",
                    "editable": true,
                    "url": 'http://foodie-dev.wirelessinfo.cz'
                },*/
                "status_manager": {
                    "title": "Status manager",
                    "type": "status_manager",
                    "editable": true,
                    "url": 'http://foodie-dev.wirelessinfo.cz'
                }
            },
            social_hashtag: 'via @opentnet',
            //compositions_catalogue_url: '/p4b-dev/cat/catalogue/libs/cswclient/cswClientRun.php',
            //compositions_catalogue_url: 'http://erra.ccss.cz/php/metadata/csw/index.php',
            //status_manager_url: '/wwwlibs/statusmanager2/index.php',

           'catalogue_url': caturl || '/php/metadata/csw/',
           'compositions_catalogue_url': caturl || '/php/metadata/csw/',
           status_manager_url: '/wwwlibs/statusmanager/index.php',

            createExtraMenu: function($compile, $scope, element) {
                $scope.uploadClicked = function() {
                    alert("UPLOAD!")
                }
                var el = angular.element("
Upload
");
                element.find('ul').append(el);
                $compile(el)($scope);
            }
        });

        module.controller('Main', ['$scope', 'Core', 'hs.query.baseService', 'hs.compositions.service_parser',
            function($scope, Core, QueryService, composition_parser) {
                if (console) console.log("Main called");
                $scope.hsl_path = hsl_path; //Get this from hslayers.js file
                $scope.Core = Core;
                Core.setMainPanel('composition_browser');
                //composition_parser.load('http://www.whatstheplan.eu/wwwlibs/statusmanager2/index.php?request=load&id=972cd7d1-e057-417b-96a7-e6bf85472b1e');
                $scope.$on('query.dataUpdated', function(event) {
                    if (console) console.log('Attributes', QueryService.data.attributes, 'Groups', QueryService.data.groups);
                });
            }
        ]);

        return module;
    });
<|endoftext|>


<commit_before>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified;

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {!Object.<SugarCrm.NameValue>}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @interface
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;
<commit_msg>refactoring app to handle more user setting.<commit_after>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified;

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {!Object.<SugarCrm.NameValue>}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmApp.ReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @interface
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;
<|endoftext|>


<commit_before>/*jslint browser: true*/
/*global jQuery */
(function ($) {
    "use strict";

    // Bootstrapper
    var InspectR = {
        // Static start function, called from main html/view to start all things up.
        start: function (config) {
            config = $.extend({}, InspectR.defaults, config);

            // main router, taking care of things
            var router = InspectR.Router = new Router(config),
                viewModel = InspectR.ViewModel = new InspectRViewModel(router, config);

            ko.applyBindings(viewModel, config.rootNode);

            // start the signalr connection
            // when the connection is successful, start the router
            $.connection.hub.start({
                    waitForPageLoad: false,
                    transport: 'longPolling'
                }, function () {
                    router.trigger('connection:start');
                    Backbone.history.start({});
                });

            // TODO: this is a work-around for signalr erroring the longPolling connection when the user navigates away from the page.
            // abort the poll on page unload, so it doesn't error.
            window.onbeforeunload = function () {
                if ($.connection.hub.pollXhr) {
                    $.connection.hub.pollXhr.abort();
                }
            };
        },
        defaults: {
            // inspector: ''
            // rootNode:'#inspectr'
        }
    };

    // Backbone Router, takes care of history
    var Router = Backbone.Router.extend({
        routes: {
            "": "start",
            "*uniquekey": "loadInspector"
        }
    });

    // Main viewmodel
    var InspectRViewModel = function (router, options) {
        var self = this,
            hub = $.connection.inspectRHub,
            client = hub.client,
            server = hub.server;

        // mixin Events
        // _.extend(this, Backbone.Events);

        // public properties
        this.NewTitle = ko.observable();
        this.IsEditingTitle = ko.observable(false);
        this.UserProfile = ko.observable();
        this.Requests = ko.mapping.fromJS([]);
        this.Inspector = ko.observable();
        this.SupportedContentTypes = _.keys(CodeMirror.mimeModes).sort();
        this.Alerts = ko.observableArray([]);

        this.RequestList = ko.computed(function () {
            return self.Requests();
        });

        /** Routes */
        router.on('connection:start', function () { self.loadUserProfile(); });

        router.on('route:start', function () {
            self.loadInspector(options.inspector);
            // router.navigate(options.inspector, { trigger: true });
        });

        this.loadInspector = function (uniquekey) {
            // self.Inspector(null); // disable this to not flicker the screen
            self.Requests([]);
            if (self.Inspector()) {
                server.stopInspect(self.Inspector().Id());
            }
            server.startInspect(uniquekey)
                .done(function (result) {
                    if (result) {
                        self.Inspector(ko.mapping.fromJS(result));
                        self.loadRecentRequests();
                    }
                });
        };
        router.on('route:loadInspector', this.loadInspector);

        /** Methods */
        this.loadRecentRequests = function () {
            server.getRecentRequests(self.Inspector().UniqueKey())
                .done(function (result) {
                    if (result && result.length > 0) {
                        ko.mapping.fromJS(result, self.Requests);
                    }
                });
        };

        this.removeInspector = function (inspector) {
            if (self.Inspector().Id() == inspector.Id()) {
                throw "Cannot remove current inspector";
            }

            if (!confirm('Remove inspector: ' + inspector.UniqueKey())) {
                return;
            }

            server.removeInspectorFromUserProfile(inspector.Id())
                .done(function () {
                    self.UserProfile().Inspectors.remove(inspector);
                });
        };

        this.saveTitle = function () {
            server.setTitle(self.Inspector().Id(), self.NewTitle())
                .done(function () {
                    self.IsEditingTitle(false);
                    self.Inspector().Title(self.NewTitle());
                    self.loadUserProfile();
                });
        };

        this.loadUserProfile = function () {
            server.getUserProfile()
                .done(function (result) {
                    if (result) {
                        self.UserProfile(ko.mapping.fromJS(result));
                    }
                });
        };

        this.clearRecentRequests = function () {
            server.clearRecentRequests(self.Inspector().UniqueKey());
            self.Requests.removeAll();
        };

        /** Hub client functions */
        client.requestLogged = function (inspector, request) {
            if (inspector.Id != self.Inspector().Id()) {
                console.log('received request for non current inspector');
                return;
            }
            self.Requests.unshift(request);
        };

        /** Private functions */
        this.showAlert = function (title, content, type) {
            var alert = new Alert(title, content, type);
            alert.closed(function () {
                self.Alerts.remove(alert);
            });
            self.Alerts.push(alert);
            return alert;
        };

        this._connectionSlow = function () {
            self.showAlert('', 'The connection is having some issues. Try refreshing this page.', Alert.warning);
        };

        this._disconnected = function () {
            self.showAlert('', 'You are disconnected. Try refreshing this page.', Alert.error);
        };

        this._connectionError = function (data) {
            if (self.ignoreConnectionErrors) {
                return;
            }
            self.ignoreConnectionErrors = true;

            self.showAlert('', 'Errors occured in the connection. Try refreshing this page.', Alert.error)
                .closed(function () {
                    self.ignoreConnectionErrors = false;
                });
        };

        // Respond to connection errors
        $.connection.hub.connectionSlow(this._connectionSlow);
        $.connection.hub.disconnected(this._disconnected);
        $.connection.hub.error(this._connectionError);
    };

    // Alert model
    var Alert = function (title, content, type) {
        var self = this;
        this.Title = ko.observable(title || '');
        this.Content = ko.observable(content || '');
        this.Type = ko.observable(type ? type : '');

        this.close = function () {
            $(self).triggerHandler('close');
        };

        this.closed = function (callback) {
            $(self).bind('close', function (e) {
                callback.call(self);
            });
        };

        this.hideAfter = function (timeout) {
            setTimeout(this.close, timeout);
        };
    };
    Alert.warning = '';
    Alert.error = 'alert-error';
    Alert.success = 'alert-success';
    Alert.info = 'alert-info';

    $.inspectR = InspectR;
}(jQuery));
<commit_msg>replace longPoll abort, doesn't work in IE.<commit_after>/*jslint browser: true*/
/*global jQuery */
(function ($) {
    "use strict";

    // Bootstrapper
    var InspectR = {
        // Static start function, called from main html/view to start all things up.
        start: function (config) {
            config = $.extend({}, InspectR.defaults, config);

            // main router, taking care of things
            var router = InspectR.Router = new Router(config),
                viewModel = InspectR.ViewModel = new InspectRViewModel(router, config);

            ko.applyBindings(viewModel, config.rootNode);

            // start the signalr connection
            // when the connection is successful, start the router
            $.connection.hub.logging = true;
            $.connection.hub.start({
                    waitForPageLoad: false,
                    transport: 'longPolling'
                }, function () {
                    router.trigger('connection:start');
                    Backbone.history.start({});
                });

            // TODO: this is a work-around for signalr erroring the longPolling connection when the user navigates away from the page.
            // abort the poll on page unload, so it doesn't error.
            window.onbeforeunload = function () {
                if ($.connection.hub.pollXhr) {
                    viewModel.ignoreConnectionErrors = true;
                }
            };
        },
        defaults: {
            // inspector: ''
            // rootNode:'#inspectr'
        }
    };

    // Backbone Router, takes care of history
    var Router = Backbone.Router.extend({
        routes: {
            "": "start",
            "*uniquekey": "loadInspector"
        }
    });

    // Main viewmodel
    var InspectRViewModel = function (router, options) {
        var self = this,
            hub = $.connection.inspectRHub,
            client = hub.client,
            server = hub.server;

        // mixin Events
        // _.extend(this, Backbone.Events);

        // public properties
        this.NewTitle = ko.observable();
        this.IsEditingTitle = ko.observable(false);
        this.UserProfile = ko.observable();
        this.Requests = ko.mapping.fromJS([]);
        this.Inspector = ko.observable();
        this.SupportedContentTypes = _.keys(CodeMirror.mimeModes).sort();
        this.Alerts = ko.observableArray([]);

        this.RequestList = ko.computed(function () {
            return self.Requests();
        });

        /** Routes */
        router.on('connection:start', function () { self.loadUserProfile(); });

        router.on('route:start', function () {
            self.loadInspector(options.inspector);
            // router.navigate(options.inspector, { trigger: true });
        });

        this.loadInspector = function (uniquekey) {
            // self.Inspector(null); // disable this to not flicker the screen
            self.Requests([]);
            if (self.Inspector()) {
                server.stopInspect(self.Inspector().Id());
            }
            server.startInspect(uniquekey)
                .done(function (result) {
                    if (result) {
                        self.Inspector(ko.mapping.fromJS(result));
                        self.loadRecentRequests();
                    }
                });
        };
        router.on('route:loadInspector', this.loadInspector);

        /** Methods */
        this.loadRecentRequests = function () {
            server.getRecentRequests(self.Inspector().UniqueKey())
                .done(function (result) {
                    if (result && result.length > 0) {
                        ko.mapping.fromJS(result, self.Requests);
                    }
                });
        };

        this.removeInspector = function (inspector) {
            if (self.Inspector().Id() == inspector.Id()) {
                throw "Cannot remove current inspector";
            }

            if (!confirm('Remove inspector: ' + inspector.UniqueKey())) {
                return;
            }

            server.removeInspectorFromUserProfile(inspector.Id())
                .done(function () {
                    self.UserProfile().Inspectors.remove(inspector);
                });
        };

        this.saveTitle = function () {
            server.setTitle(self.Inspector().Id(), self.NewTitle())
                .done(function () {
                    self.IsEditingTitle(false);
                    self.Inspector().Title(self.NewTitle());
                    self.loadUserProfile();
                });
        };

        this.loadUserProfile = function () {
            server.getUserProfile()
                .done(function (result) {
                    if (result) {
                        self.UserProfile(ko.mapping.fromJS(result));
                    }
                });
        };

        this.clearRecentRequests = function () {
            server.clearRecentRequests(self.Inspector().UniqueKey());
            self.Requests.removeAll();
        };

        /** Hub client functions */
        client.requestLogged = function (inspector, request) {
            if (inspector.Id != self.Inspector().Id()) {
                console.log('received request for non current inspector');
                return;
            }
            self.Requests.unshift(request);
        };

        /** Private functions */
        this.showAlert = function (title, content, type) {
            var alert = new Alert(title, content, type);
            alert.closed(function () {
                self.Alerts.remove(alert);
            });
            self.Alerts.push(alert);
            return alert;
        };

        this._connectionSlow = function () {
            self.showAlert('', 'The connection is having some issues. Try refreshing this page.', Alert.warning);
        };

        this._disconnected = function () {
            self.showAlert('', 'You are disconnected. Try refreshing this page.', Alert.error);
        };

        this._connectionError = function (data) {
            if (self.ignoreConnectionErrors) {
                return;
            }
            self.ignoreConnectionErrors = true;

            self.showAlert('', 'Errors occured in the connection. Try refreshing this page.', Alert.error)
                .closed(function () {
                    self.ignoreConnectionErrors = false;
                });
        };

        // Respond to connection errors
        $.connection.hub.connectionSlow(this._connectionSlow);
        $.connection.hub.disconnected(this._disconnected);
        $.connection.hub.error(this._connectionError);
    };

    // Alert model
    var Alert = function (title, content, type) {
        var self = this;
        this.Title = ko.observable(title || '');
        this.Content = ko.observable(content || '');
        this.Type = ko.observable(type ? type : '');

        this.close = function () {
            $(self).triggerHandler('close');
        };

        this.closed = function (callback) {
            $(self).bind('close', function (e) {
                callback.call(self);
            });
        };

        this.hideAfter = function (timeout) {
            setTimeout(this.close, timeout);
        };
    };
    Alert.warning = '';
    Alert.error = 'alert-error';
    Alert.success = 'alert-success';
    Alert.info = 'alert-info';

    $.inspectR = InspectR;
}(jQuery));
<|endoftext|>


<commit_before>'use strict';

// You can set the following environment variable to generate more verbose debug
// output for nock
//   env DEBUG='nock*' make test

const fs = require('fs');
const nock = require('nock');
const path = require('path');
const K8s = require('../../../../../../../lib/cluster/services/cluster/backends/kubernetes/k8s');

function print(err, result) {
    // FIXME: How much does this smell, do we have an existing convention?
    if (process.env.DEBUG) {
        console.error(JSON.stringify(err || result, null, 2)); // eslint-disable-line no-console
    }
}

const logger = {
    debug: print,
    info: print,
    warn: print,
    error: print
};

const swaggerFile = path.join(__dirname, 'files', 'swagger.json');

const _url = 'http://mock.kube.api';
// const _url = 'https://192.168.99.100:8443';

// FIXME: Remember, I break unit tests if I leave this in!!
fdescribe('k8s', () => {
    let k8s;

    beforeEach(async () => {
        nock(_url)
            .get('/swagger.json')
            .reply(200, fs.readFileSync(swaggerFile, 'utf-8'))
            .get('/api/v1/namespaces')
            .reply(200, {
                kind: 'NamespaceList',
                apiVersion: 'v1',
                metadata: {
                    selfLink: '/api/v1/namespaces',
                    resourceVersion: '1961000'
                },
                items: [
                    {
                        metadata: {
                            name: 'default'
                        }
                    }
                ]
            });

        const clientConfig = {
            url: _url,
            auth: {
                user: 'admin',
                pass: 'fakepass',
            },
            insecureSkipTlsVerify: true,
        };
        k8s = new K8s(logger, clientConfig);
        await k8s.init();
    });

    afterEach(() => {
        nock.cleanAll();
    });

    it('can get the "default" namespace', async () => {
        const namespaces = await k8s.getNamespaces();
        expect(namespaces.items[0].metadata.name).toEqual('default');
    });

    describe('->list', () => {
        beforeEach(() => {
            nock(_url)
                .get('/api/v1/namespaces/default/pods/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'PodList' })
                .get('/apis/apps/v1/namespaces/default/deployments/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'DeploymentList' })
                .get('/apis/v1/namespaces/default/services/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'ServiceList' })
                .get('/apis/batch/v1/namespaces/default/jobs/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'JobList' });
        });

        it('can get PodList', async () => {
            const pods = await k8s.list('app=teraslice', 'pods');
            expect(pods.kind).toEqual('PodList');
        });

        it('can get DeploymentList', async () => {
            const deployments = await k8s.list('app=teraslice', 'deployments');
            expect(deployments.kind).toEqual('DeploymentList');
        });

        it('can get JobList', async () => {
            const jobs = await k8s.list('app=teraslice', 'jobs');
            expect(jobs.kind).toEqual('JobList');
        });
    });

    describe('->post', () => {
        beforeEach(() => {
            nock(_url, { encodedQueryParams: true })
                .post('/api/v1/namespaces/default/services')
                .reply(201, { kind: 'Service' })
                .post('/apis/apps/v1/namespaces/default/deployments')
                .reply(201, { kind: 'Deployment' });
        });

        it('can post a service', async () => {
            const response = await k8s.post({ kind: 'Service' }, 'service');
            expect(response.kind).toEqual('Service');
        });

        it('can post a deployment', async () => {
            const response = await k8s.post({ kind: 'Deployment' }, 'deployment');
            expect(response.kind).toEqual('Deployment');
        });
    });

    describe('->patch', () => {
        beforeEach(() => {
            nock(_url, { encodedQueryParams: true })
                .patch('/apis/apps/v1/namespaces/default/deployments/test1')
                .reply(204, { });
        });

        it('can patch a deployment by name', async () => {
            const response = await k8s.patch({ name: 'testName' }, 'test1');
            expect(response).toEqual({});
        });
    });

    describe('->delete', () => {
        it('can delete a deployment by name', async () => {
            nock(_url)
                .delete('/apis/apps/v1/namespaces/default/deployments/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'deployments');
            expect(response).toEqual({});
        });

        it('can delete a service by name', async () => {
            nock(_url)
                .delete('/api/v1/namespaces/default/services/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'services');
            expect(response).toEqual({});
        });

        it('can delete a job by name', async () => {
            nock(_url)
                .delete('/apis/batch/v1/namespaces/default/jobs/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'jobs');
            expect(response).toEqual({});
        });
    });

    describe('->scaleExecution', () => {
        let scope;

        beforeEach(() => {
            scope = nock(_url)
                .get('/apis/apps/v1/namespaces/default/deployments/')
                .query({ labelSelector: /nodeType=worker,exId=.*/ })
                .reply(200, {
                    kind: 'DeploymentList',
                    items: [
                        { spec: { replicas: 5 }, metadata: { name: 'dname' } }
                    ]
                });
        });

        it('can set nodes to a deployment to 2', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 2,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'set');
            expect(response.spec.replicas).toEqual(2);
        });

        it('can add 2 nodes to a deployment with 5 to get 7', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 7,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'add');
            expect(response.spec.replicas).toEqual(7);
        });

        it('can remove 2 nodes from a deployment with 5 to get 3', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 3,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'remove');
            expect(response.spec.replicas).toEqual(3);
        });
    });
});
<commit_msg>Reorganized nocks and added missing serviceList test<commit_after>'use strict';

// You can set the following environment variable to generate more verbose debug
// output for nock
//   env DEBUG='nock*' make test

const fs = require('fs');
const nock = require('nock');
const path = require('path');
const K8s = require('../../../../../../../lib/cluster/services/cluster/backends/kubernetes/k8s');

function print(err, result) {
    // FIXME: How much does this smell, do we have an existing convention?
    if (process.env.DEBUG) {
        console.error(JSON.stringify(err || result, null, 2)); // eslint-disable-line no-console
    }
}

const logger = {
    debug: print,
    info: print,
    warn: print,
    error: print
};

const swaggerFile = path.join(__dirname, 'files', 'swagger.json');

const _url = 'http://mock.kube.api';
// const _url = 'https://192.168.99.100:8443';

// FIXME: Remember, I break unit tests if I leave this in!!
fdescribe('k8s', () => {
    let k8s;

    beforeEach(async () => {
        nock(_url)
            .get('/swagger.json')
            .reply(200, fs.readFileSync(swaggerFile, 'utf-8'))
            .get('/api/v1/namespaces')
            .reply(200, {
                kind: 'NamespaceList',
                apiVersion: 'v1',
                metadata: {
                    selfLink: '/api/v1/namespaces',
                    resourceVersion: '1961000'
                },
                items: [
                    {
                        metadata: {
                            name: 'default'
                        }
                    }
                ]
            });

        const clientConfig = {
            url: _url,
            auth: {
                user: 'admin',
                pass: 'fakepass',
            },
            insecureSkipTlsVerify: true,
        };
        k8s = new K8s(logger, clientConfig);
        await k8s.init();
    });

    afterEach(() => {
        nock.cleanAll();
    });

    it('can get the "default" namespace', async () => {
        const namespaces = await k8s.getNamespaces();
        expect(namespaces.items[0].metadata.name).toEqual('default');
    });

    describe('->list', () => {
        it('can get PodList', async () => {
            nock(_url)
                .get('/api/v1/namespaces/default/pods/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'PodList' });
            const pods = await k8s.list('app=teraslice', 'pods');
            expect(pods.kind).toEqual('PodList');
        });

        it('can get ServiceList', async () => {
            nock(_url)
                .get('/api/v1/namespaces/default/services/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'ServiceList' });
            const pods = await k8s.list('app=teraslice', 'services');
            expect(pods.kind).toEqual('ServiceList');
        });

        it('can get DeploymentList', async () => {
            nock(_url)
                .get('/apis/apps/v1/namespaces/default/deployments/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'DeploymentList' });
            const deployments = await k8s.list('app=teraslice', 'deployments');
            expect(deployments.kind).toEqual('DeploymentList');
        });

        it('can get JobList', async () => {
            nock(_url)
                .get('/apis/batch/v1/namespaces/default/jobs/')
                .query({ labelSelector: 'app=teraslice' })
                .reply(200, { kind: 'JobList' });
            const jobs = await k8s.list('app=teraslice', 'jobs');
            expect(jobs.kind).toEqual('JobList');
        });
    });

    describe('->post', () => {
        beforeEach(() => {
            nock(_url, { encodedQueryParams: true })
                .post('/api/v1/namespaces/default/services')
                .reply(201, { kind: 'Service' })
                .post('/apis/apps/v1/namespaces/default/deployments')
                .reply(201, { kind: 'Deployment' });
        });

        it('can post a service', async () => {
            const response = await k8s.post({ kind: 'Service' }, 'service');
            expect(response.kind).toEqual('Service');
        });

        it('can post a deployment', async () => {
            const response = await k8s.post({ kind: 'Deployment' }, 'deployment');
            expect(response.kind).toEqual('Deployment');
        });
    });

    describe('->patch', () => {
        beforeEach(() => {
            nock(_url, { encodedQueryParams: true })
                .patch('/apis/apps/v1/namespaces/default/deployments/test1')
                .reply(204, { });
        });

        it('can patch a deployment by name', async () => {
            const response = await k8s.patch({ name: 'testName' }, 'test1');
            expect(response).toEqual({});
        });
    });

    describe('->delete', () => {
        it('can delete a deployment by name', async () => {
            nock(_url)
                .delete('/apis/apps/v1/namespaces/default/deployments/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'deployments');
            expect(response).toEqual({});
        });

        it('can delete a service by name', async () => {
            nock(_url)
                .delete('/api/v1/namespaces/default/services/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'services');
            expect(response).toEqual({});
        });

        it('can delete a job by name', async () => {
            nock(_url)
                .delete('/apis/batch/v1/namespaces/default/jobs/test1')
                .reply(200, { });

            const response = await k8s.delete('test1', 'jobs');
            expect(response).toEqual({});
        });
    });

    describe('->scaleExecution', () => {
        let scope;

        beforeEach(() => {
            scope = nock(_url)
                .get('/apis/apps/v1/namespaces/default/deployments/')
                .query({ labelSelector: /nodeType=worker,exId=.*/ })
                .reply(200, {
                    kind: 'DeploymentList',
                    items: [
                        { spec: { replicas: 5 }, metadata: { name: 'dname' } }
                    ]
                });
        });

        it('can set nodes to a deployment to 2', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 2,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'set');
            expect(response.spec.replicas).toEqual(2);
        });

        it('can add 2 nodes to a deployment with 5 to get 7', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 7,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'add');
            expect(response.spec.replicas).toEqual(7);
        });

        it('can remove 2 nodes from a deployment with 5 to get 3', async () => {
            scope.patch('/apis/apps/v1/namespaces/default/deployments/dname', {
                spec: {
                    replicas: 3,
                }
            }).reply(200, (uri, requestBody) => requestBody);

            const response = await k8s.scaleExecution('abcde1234', 2, 'remove');
            expect(response.spec.replicas).toEqual(3);
        });
    });
});
<|endoftext|>


<commit_before>/* Omega Jump Gate Command Operations
 *
 * Copyright (C) 2014 Mohammed Morsi <mo@morsi.org>
 *  Licensed under the AGPLv3 http://www.gnu.org/licenses/agpl.txt
 */

//= require "ui/command_dialog"

Omega.JumpGateCommands = {
  has_details : true,

  retrieve_details : function(page, details_cb){
    var title = 'Jump Gate to ' + this.endpoint_title();
    var loc   = '@ ' + this.location.to_s();
    var trigger_cmd   = $('',
      {id    : 'trigger_jg_' + this.id,
       class : 'trigger_jg details_command',
       text  : 'trigger'});
    trigger_cmd.data('jump_gate', this);

    var _this = this;
    trigger_cmd.click(function(){ _this._trigger(page); });

    /// exclude trigger_cmd if page.session is null
    var details_text = title + '
' + loc + '

';
    var details = page.session ? [details_text, trigger_cmd] : [details_text];
    details_cb(details);
  },

  dialog : function(){
    return Omega.UI.CommandDialog.instance();
  },

  _trigger : function(page){
    var _this = this;
    var ships = $.grep(page.all_entities(), function(e){
                  return _this._should_trigger_ship(e, page);
                });

    for(var s = 0; s < ships.length; s++){
      var ship = ships[s];
      (function(ship){ /// XXX need new scope to preserve ship
        /// XXX make sure endpoint is set! (won't come in w/ server jg)
        ship.location.parent_id = _this.endpoint.location.id;
        page.node.http_invoke('manufactured::move_entity', ship.id, ship.location,
          function(response){
            if(response.error){
              _this.dialog().title = 'Jump Gate Trigger Error';
              _this.dialog().show_error_dialog();
              _this.dialog().append_error(response.error.message);

            }else{
              ship.system_id = _this.endpoint_id;
              page.canvas.remove(ship);
              page.audio_controls.play(_this.trigger_audio);
              /// TODO reset ship gfx (eg reset visited route)
            }
          });
       })(ship);
    }
  },

  _should_trigger_ship : function(entity, page){
    return entity.json_class == 'Manufactured::Ship' &&
           entity.belongs_to_user(page.session.user_id) &&
           entity.location.is_within(this.trigger_distance,
                                     this.location);
  }
};
<commit_msg>UI: refactor jg trigger methods, invoke ship.update_jump_gfx<commit_after>/* Omega Jump Gate Command Operations
 *
 * Copyright (C) 2014 Mohammed Morsi <mo@morsi.org>
 *  Licensed under the AGPLv3 http://www.gnu.org/licenses/agpl.txt
 */

//= require "ui/command_dialog"

Omega.JumpGateCommands = {
  has_details : true,

  retrieve_details : function(page, details_cb){
    var title = 'Jump Gate to ' + this.endpoint_title();
    var loc   = '@ ' + this.location.to_s();
    var trigger_cmd   = $('',
      {id    : 'trigger_jg_' + this.id,
       class : 'trigger_jg details_command',
       text  : 'trigger'});
    trigger_cmd.data('jump_gate', this);

    var _this = this;
    trigger_cmd.click(function(){ _this._trigger(page); });

    /// exclude trigger_cmd if page.session is null
    var details_text = title + '
' + loc + '

';
    var details = page.session ? [details_text, trigger_cmd] : [details_text];
    details_cb(details);
  },

  dialog : function(){
    return Omega.UI.CommandDialog.instance();
  },

  _trigger : function(page){
    var _this = this;
    var ships = $.grep(page.all_entities(), function(e){
                  return _this._should_trigger_ship(e, page);
                });

    for(var s = 0; s < ships.length; s++)
      this._trigger_ship(ships[s], page);
  },

  _trigger_ship : function(ship, page){
    var _this = this;

    /// FIXME make sure endpoint is set! (won't come in w/ server jg)
    ship.location.parent_id = _this.endpoint.location.id;
    page.node.http_invoke('manufactured::move_entity', ship.id, ship.location,
      function(response){
        if(response.error)
          _this._trigger_ship_failed(response);
        else
          _this._trigger_ship_success(ship, page);
      });
  },

  _trigger_ship_failed : function(response){
    this.dialog().title = 'Jump Gate Trigger Error';
    this.dialog().show_error_dialog();
    this.dialog().append_error(response.error.message);
  },

  _trigger_ship_success : function(ship, page){
    /// FIXME need to set system itself
    ship.system_id = this.endpoint_id;
    page.canvas.remove(ship);
    page.audio_controls.play(this.trigger_audio);
    ship.update_jump_gfx();
  },

  _should_trigger_ship : function(entity, page){
    return entity.json_class == 'Manufactured::Ship' &&
           entity.belongs_to_user(page.session.user_id) &&
           entity.location.is_within(this.trigger_distance,
                                     this.location);
  }
};
<|endoftext|>


<commit_before>/**
 * Chat plug-ins
 * Pokemon Showdown - http://pokemonshowdown.com/
 *
 * These are chat plugins - small programs to enhace the chat rooms on Pokemon Showdown.
 * Plugins are objects inside the plugins object. The objects are expected to have data values and a commands object inside.
 * The data object saves the data relevant to the plugin, like scores.
 * The commands object is used to import the commands onto the chat commands.
 * It's very important that you don't add plug-in commands with the same name as existing commands.
 *
 * @license MIT license
 */

var plugins = exports.plugins = {
	/**
	 * Scavenger hunts plugin.
	 * This game is meant to show a first hint. Players will find the name of a room with that hint.
	 * When you find a room, it gives you a hint for the next room.
	 * You finish upon reaching the third room.
	 * This plugin requires the server to have a room with the id 'scavengers'.
	 */
	scavenger: {
		status: 'off',
		firstHint: '',
		roomOne: '',
		secondHint: '',
		roomTwo: '',
		thirdHint: '',
		roomThree: '',
		participants: {},
		finished: [],
		commands: {
			scavengerstarthunt: function (target, room, user) {
				if (!this.can('ban', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only start scavenger hunts on Scavengers room.');
				if (plugins.scavenger.status === 'on') return this.sendReply('There is already an active scavenger hunt.');
				var targets = target.split(',');
				if (!targets[0] || !targets[1] || !targets[2] || !targets[3] || !targets[4] || !targets[5])
					return this.sendReply('You need to add three rooms and three hints in a [room, hint,] format.');
				plugins.scavenger.status = 'on';
				plugins.scavenger.roomOne = toId(targets[0]);
				plugins.scavenger.firstHint = targets[1].trim();
				plugins.scavenger.roomTwo = toId(targets[2]);
				plugins.scavenger.secondHint = targets[3].trim();
				plugins.scavenger.roomThree = toId(targets[4]);
				plugins.scavenger.thirdHint = targets[5].trim();
				if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add(
					'|raw|
A new Scavenger Hunt has been started!'
					+ ' The first hint is: ' + plugins.scavenger.firstHint + '
'
				);
				return this.sendReply('Scavenger hunt started.');
			},
			scavengerendhunt: function (target, room, user) {
				if (!this.can('ban', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only end scavenger hunts on Scavengers room.');
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt.');
				var result = '';
				var winner = plugins.scavenger.finished[0];
				var second = plugins.scavenger.finished[1];
				var third = plugins.scavenger.finished[2];
				var consolation = plugins.scavenger.finished.slice(3);
				result += 'Winner of Scavenger Hunt: ' + ((winner)? sanitize(winner) : 'no one') + '.';
				result += ' Second place: ' + ((second)? sanitize(second) : 'no one') + '.';
				result += ' Third place: ' + ((third)? sanitize(third) : 'no one') + '.';
				result += ' Consolation prize to: ' + ((consolation.length > 0)? sanitize(consolation.join(', ')) : 'no one') + '.';
				result += '
Solution: ' + plugins.scavenger.roomOne + ', '
				+ plugins.scavenger.roomTwo + ', ' + plugins.scavenger.roomThree + '.';
				if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add('|raw|
' + result + '
');
				this.parse('/scavengerresethunt');
				return this.sendReply('Scavenger hunt finished.');
			},
			scavengerresethunt: function (target, room, user) {
				if (!this.can('ban', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only reset scavenger hunts on Scavengers room.');
				plugins.scavenger.status = 'off';
				plugins.scavenger.roomOne = '';
				plugins.scavenger.roomTwo = '';
				plugins.scavenger.roomThree = '';
				plugins.scavenger.firstHint = '';
				plugins.scavenger.secondHint = '';
				plugins.scavenger.thirdHint = '';
				plugins.scavenger.participants = {};
				plugins.scavenger.finished = [];
				return this.sendReply('Scavenger hunt reset.');
			},
			scavenger: 'scavengers',
			scavengers: function (target, room, user) {
				return this.parse('/join scavengers');
			},
			scavengerhint: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				if (plugins.scavenger.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
				return this.sendReply(
					'Your current hint: '
					+ plugins.scavenger[{0:'firstHint', 1:'secondHint', 2:'thirdHint'}[plugins.scavenger.participants[user.userid].room]]
					+ '. Type /scavenge [solution] to find out if you are right.'
				);
			},
			scavenge: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				if (plugins.scavenger.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
				target = toId(target);
				var room = plugins.scavenger.participants[user.userid].room;
				if (plugins.scavenger[{0:'roomOne', 1:'roomTwo', 2:'roomThree'}[room]] === target) {
					plugins.scavenger.participants[user.userid].room++;
					room++;
					if (room < 3) {
						var currentHint = {1:'secondHint', 2:'thirdHint'};
						return this.sendReply(
							'Well done! You have advanced to the next room! The next hint is: '
							+ plugins.scavenger[currentHint[room]]
						);
					} else {
						// User finished, let's check the result
						plugins.scavenger.finished.push(user.name);
						var winningPositions = {1:'winner', 2:'second', 3:'third'};
						var position = plugins.scavenger.finished.length;
						var result = 'The user ' + sanitize(user.name) + ' has finished the hunt! (S)he is the '
						+ ((winningPositions[position])? winningPositions[position] : position + 'th') + '!';
						if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add(
							'|raw|
' + result + '
'
						);
					}
				} else {
					return this.sendReply('Fat luck - that is not the next room!');
				}
			},
			joinhunt: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (plugins.scavenger.participants[user.userid]) return this.sendReply('You are already participating in the current scavenger hunt.');
				plugins.scavenger.participants[user.userid] = {id: user.userid, room: 0};
				return this.sendReply('You joined the scavenger hunt! Type /scavenge name to try to find the room and /scavengerhint to read your current hint.');
			},
			scavengerstatus: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				var currentHint = {0:'firstHint', 1:'secondHint', 2:'thirdHint'};
				var room = plugins.scavenger.participants[user.userid].room;
				return this.sendReply(
					'Your current hunt status: You are in the room #' + room + ((room < 3)? '. Your current hint is '
					+ plugins.scavenger[currentHint[room]] : '. You have finished') + '.'
				);
			},
			scavengerhelp: function (target, room, user) {
				if (room.id !== 'scavengers') return;
				if (!this.canBroadcast()) return;
				this.sendReplyBox(
					'Player commands:
' +
					'- /scavengers: Join the scavengers room
' +
					'- /joinhunt: Join the current hunt
' +
					'- /scavengerhint: Get your current hint
' +
					'- /scavengerstatus: Get your current game status
' +
					'- /scavenge name: Test the [name] to find a room
' +
					'
' +
					'Admin commands:
' +
					'- /scavengerstarthunt room one, hint, room two, hint, room three, hint: Start a new hunt
' +
					'- /scavengerendhunt: Finish current hunt and announce winners
' +
					'- /scavengerresethunt: Reset the current hunt to mint status'
				);
			}
		}
	}
};
<commit_msg>Allow % to run scavenger hunts<commit_after>/**
 * Chat plug-ins
 * Pokemon Showdown - http://pokemonshowdown.com/
 *
 * These are chat plugins - small programs to enhace the chat rooms on Pokemon Showdown.
 * Plugins are objects inside the plugins object. The objects are expected to have data values and a commands object inside.
 * The data object saves the data relevant to the plugin, like scores.
 * The commands object is used to import the commands onto the chat commands.
 * It's very important that you don't add plug-in commands with the same name as existing commands.
 *
 * @license MIT license
 */

var plugins = exports.plugins = {
	/**
	 * Scavenger hunts plugin.
	 * This game is meant to show a first hint. Players will find the name of a room with that hint.
	 * When you find a room, it gives you a hint for the next room.
	 * You finish upon reaching the third room.
	 * This plugin requires the server to have a room with the id 'scavengers'.
	 */
	scavenger: {
		status: 'off',
		firstHint: '',
		roomOne: '',
		secondHint: '',
		roomTwo: '',
		thirdHint: '',
		roomThree: '',
		participants: {},
		finished: [],
		commands: {
			scavengerstarthunt: function (target, room, user) {
				if (!this.can('mute', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only start scavenger hunts on Scavengers room.');
				if (plugins.scavenger.status === 'on') return this.sendReply('There is already an active scavenger hunt.');
				var targets = target.split(',');
				if (!targets[0] || !targets[1] || !targets[2] || !targets[3] || !targets[4] || !targets[5])
					return this.sendReply('You need to add three rooms and three hints in a [room, hint,] format.');
				plugins.scavenger.status = 'on';
				plugins.scavenger.roomOne = toId(targets[0]);
				plugins.scavenger.firstHint = targets[1].trim();
				plugins.scavenger.roomTwo = toId(targets[2]);
				plugins.scavenger.secondHint = targets[3].trim();
				plugins.scavenger.roomThree = toId(targets[4]);
				plugins.scavenger.thirdHint = targets[5].trim();
				if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add(
					'|raw|
A new Scavenger Hunt has been started!'
					+ ' The first hint is: ' + plugins.scavenger.firstHint + '
'
				);
				return this.sendReply('Scavenger hunt started.');
			},
			scavengerendhunt: function (target, room, user) {
				if (!this.can('mute', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only end scavenger hunts on Scavengers room.');
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt.');
				var result = '';
				var winner = plugins.scavenger.finished[0];
				var second = plugins.scavenger.finished[1];
				var third = plugins.scavenger.finished[2];
				var consolation = plugins.scavenger.finished.slice(3);
				result += 'Winner of Scavenger Hunt: ' + ((winner)? sanitize(winner) : 'no one') + '.';
				result += ' Second place: ' + ((second)? sanitize(second) : 'no one') + '.';
				result += ' Third place: ' + ((third)? sanitize(third) : 'no one') + '.';
				result += ' Consolation prize to: ' + ((consolation.length > 0)? sanitize(consolation.join(', ')) : 'no one') + '.';
				result += '
Solution: ' + plugins.scavenger.roomOne + ', '
				+ plugins.scavenger.roomTwo + ', ' + plugins.scavenger.roomThree + '.';
				if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add('|raw|
' + result + '
');
				this.parse('/scavengerresethunt');
				return this.sendReply('Scavenger hunt finished.');
			},
			scavengerresethunt: function (target, room, user) {
				if (!this.can('mute', null, room)) return false;
				if (room.id !== 'scavengers') return this.sendReply('You can only reset scavenger hunts on Scavengers room.');
				plugins.scavenger.status = 'off';
				plugins.scavenger.roomOne = '';
				plugins.scavenger.roomTwo = '';
				plugins.scavenger.roomThree = '';
				plugins.scavenger.firstHint = '';
				plugins.scavenger.secondHint = '';
				plugins.scavenger.thirdHint = '';
				plugins.scavenger.participants = {};
				plugins.scavenger.finished = [];
				return this.sendReply('Scavenger hunt reset.');
			},
			scavenger: 'scavengers',
			scavengers: function (target, room, user) {
				return this.parse('/join scavengers');
			},
			scavengerhint: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				if (plugins.scavenger.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
				return this.sendReply(
					'Your current hint: '
					+ plugins.scavenger[{0:'firstHint', 1:'secondHint', 2:'thirdHint'}[plugins.scavenger.participants[user.userid].room]]
					+ '. Type /scavenge [solution] to find out if you are right.'
				);
			},
			scavenge: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				if (plugins.scavenger.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
				target = toId(target);
				var room = plugins.scavenger.participants[user.userid].room;
				if (plugins.scavenger[{0:'roomOne', 1:'roomTwo', 2:'roomThree'}[room]] === target) {
					plugins.scavenger.participants[user.userid].room++;
					room++;
					if (room < 3) {
						var currentHint = {1:'secondHint', 2:'thirdHint'};
						return this.sendReply(
							'Well done! You have advanced to the next room! The next hint is: '
							+ plugins.scavenger[currentHint[room]]
						);
					} else {
						// User finished, let's check the result
						plugins.scavenger.finished.push(user.name);
						var winningPositions = {1:'winner', 2:'second', 3:'third'};
						var position = plugins.scavenger.finished.length;
						var result = 'The user ' + sanitize(user.name) + ' has finished the hunt! (S)he is the '
						+ ((winningPositions[position])? winningPositions[position] : position + 'th') + '!';
						if (Rooms.rooms.scavengers) Rooms.rooms.scavengers.add(
							'|raw|
' + result + '
'
						);
					}
				} else {
					return this.sendReply('Fat luck - that is not the next room!');
				}
			},
			joinhunt: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (plugins.scavenger.participants[user.userid]) return this.sendReply('You are already participating in the current scavenger hunt.');
				plugins.scavenger.participants[user.userid] = {id: user.userid, room: 0};
				return this.sendReply('You joined the scavenger hunt! Type /scavenge name to try to find the room and /scavengerhint to read your current hint.');
			},
			scavengerstatus: function (target, room, user) {
				if (plugins.scavenger.status !== 'on') return this.sendReply('There is no active scavenger hunt right now.');
				if (!plugins.scavenger.participants[user.userid]) return this.sendReply('You are not participating in the current scavenger hunt.');
				var currentHint = {0:'firstHint', 1:'secondHint', 2:'thirdHint'};
				var room = plugins.scavenger.participants[user.userid].room;
				return this.sendReply(
					'Your current hunt status: You are in the room #' + room + ((room < 3)? '. Your current hint is '
					+ plugins.scavenger[currentHint[room]] : '. You have finished') + '.'
				);
			},
			scavengerhelp: function (target, room, user) {
				if (room.id !== 'scavengers') return;
				if (!this.canBroadcast()) return;
				this.sendReplyBox(
					'Player commands:
' +
					'- /scavengers: Join the scavengers room
' +
					'- /joinhunt: Join the current hunt
' +
					'- /scavengerhint: Get your current hint
' +
					'- /scavengerstatus: Get your current game status
' +
					'- /scavenge name: Test the [name] to find a room
' +
					'
' +
					'Admin commands:
' +
					'- /scavengerstarthunt room one, hint, room two, hint, room three, hint: Start a new hunt
' +
					'- /scavengerendhunt: Finish current hunt and announce winners
' +
					'- /scavengerresethunt: Reset the current hunt to mint status'
				);
			}
		}
	}
};
<|endoftext|>


<commit_before>var xor = function (a, b) {return !a ^ !b;};
var isArray = function (a) {
    try {
        return Object.toString.call(a) === "[object Array]" || Object.toString.call(a) === "[object RuntimeArray]";
    } catch (e) {
        return Array.isArray(a);
    }
};
var recursive_compare = function(a, b) {
    // Recursively compare two objects.
    var same = true;
    same = same && !xor(a instanceof Object || typeof a == 'object', b instanceof Object || typeof b == 'object');
    same = same && !xor(isArray(a), isArray(b));

    if (same) {
        if (a instanceof Object) {
            var key;
            for (key in a) {
                if (a.hasOwnProperty(key) && !recursive_compare(a[key], b[key])) {
                    same = false;
                    break;
                }
            }
            for (key in b) {
                if (b.hasOwnProperty(key) && !recursive_compare(a[key], b[key])) {
                    same = false;
                    break;
                }
            }
        } else {
            return a === b;
        }
    }

    return same;
};

// Test the widget framework.
casper.notebook_test(function () {
    var index;

    index = this.append_cell(
        ['from IPython.html import widgets',
         'from IPython.display import display, clear_output',
         'print("Success")'].join('\n'));
    this.execute_cell_then(index);

    this.then(function () {
        // Test multi-set, single touch code.  First create a custom widget.
        this.thenEvaluate(function() {
            var MultiSetView = IPython.DOMWidgetView.extend({
                render: function(){
                    this.model.set('a', 1);
                    this.model.set('b', 2);
                    this.model.set('c', 3);
                    this.touch();
                },
            });
            IPython.WidgetManager.register_widget_view('MultiSetView', MultiSetView);
        }, {});
    });

    // Try creating the multiset widget, verify that sets the values correctly.
    var multiset = {};
    multiset.index = this.append_cell([
        'from IPython.utils.traitlets import Unicode, CInt',
        'class MultiSetWidget(widgets.Widget):',
        '    _view_name = Unicode("MultiSetView", sync=True)',
        '    a = CInt(0, sync=True)',
        '    b = CInt(0, sync=True)',
        '    c = CInt(0, sync=True)',
        '    d = CInt(-1, sync=True)', // See if it sends a full state.
        '    def set_state(self, sync_data):',
        '        widgets.Widget.set_state(self, sync_data)',
        '        self.d = len(sync_data)',
        'multiset = MultiSetWidget()',
        'display(multiset)',
        'print(multiset.model_id)'].join('\n'));
    this.execute_cell_then(multiset.index, function(index) {
        multiset.model_id = this.get_output_cell(index).text.trim();
    });

    this.wait_for_widget(multiset);

    index = this.append_cell(
        'print("%d%d%d" % (multiset.a, multiset.b, multiset.c))');
    this.execute_cell_then(index, function(index) {
        this.test.assertEquals(this.get_output_cell(index).text.trim(), '123',
            'Multiple model.set calls and one view.touch update state in back-end.');
    });

    index = this.append_cell(
        'print("%d" % (multiset.d))');
    this.execute_cell_then(index, function(index) {
        this.test.assertEquals(this.get_output_cell(index).text.trim(), '3',
            'Multiple model.set calls sent a partial state.');
    });

    var textbox = {};
    throttle_index = this.append_cell([
        'import time',
        'textbox = widgets.Text()',
        'display(textbox)',
        'textbox._dom_classes = ["my-throttle-textbox"]',
        'def handle_change(name, old, new):',
        '    display(len(new))',
        '    time.sleep(0.5)',
        'textbox.on_trait_change(handle_change, "value")',
        'print(textbox.model_id)'].join('\n'));
    this.execute_cell_then(throttle_index, function(index){
        textbox.model_id = this.get_output_cell(index).text.trim();

        this.test.assert(this.cell_element_exists(index,
            '.widget-area .widget-subarea'),
            'Widget subarea exists.');

        this.test.assert(this.cell_element_exists(index,
            '.my-throttle-textbox'), 'Textbox exists.');

        // Send 20 characters
        this.sendKeys('.my-throttle-textbox input', '12345678901234567890');
    });

    this.wait_for_widget(textbox);

    this.then(function () {
        var outputs = this.evaluate(function(i) {
            return IPython.notebook.get_cell(i).output_area.outputs;
        }, {i : throttle_index});

        // Only 4 outputs should have printed, but because of timing, sometimes
        // 5 outputs will print.  All we need to do is verify num outputs <= 5
        // because that is much less than 20.
        this.test.assert(outputs.length <= 5, 'Messages throttled.');

        // We also need to verify that the last state sent was correct.
        var last_state = outputs[outputs.length-1].data['text/plain'];
        this.test.assertEquals(last_state, "20", "Last state sent when throttling.");
    });

    this.thenEvaluate(function() {
        define('TestWidget', ['widgets/js/widget', 'base/js/utils'], function(widget, utils) {
            var TestWidget = widget.DOMWidgetView.extend({
                render: function () {
                    this.listenTo(this.model, 'msg:custom', this.handle_msg);
                },
                handle_msg: function(content, buffers) {
                    this.msg = [content, buffers];
                }
            });

            var floatArray = {
                deserialize: function (value, model) {
                    // DataView -> float64 typed array
                    return new Float64Array(value.buffer);
                },
                // serialization automatically handled by message buffers
            };

            var floatList = {
                deserialize: function (value, model) {
                    // list of floats -> list of strings
                    return value.map(function(x) {return x.toString()});
                },
                serialize: function(value, model) {
                    // list of strings -> list of floats
                    return value.map(function(x) {return parseFloat(x);})
                }
            };
            return {TestWidget: TestWidget, floatArray: floatArray, floatList: floatList};
        });
    });

    var testwidget = {};
    this.append_cell_execute_then([
        'from IPython.html import widgets',
        'from IPython.utils.traitlets import Unicode, Instance, List',
        'from IPython.display import display',
        'from array import array',
        'def _array_to_memoryview(x):',
        '    if x is None: return None, {}',
        '    try:',
        '        y = memoryview(x)',
        '    except TypeError:',
        "        # in python 2, arrays don't support the new buffer protocol",
        '        y = memoryview(buffer(x))',
        "    return y, {'serialization': ('floatArray', 'TestWidget')}",
        'def _memoryview_to_array(x):',
        "    return array('d', x.tobytes())",
        'arrays_binary = {',
        "    'from_json': _memoryview_to_array,",
        "    'to_json': _array_to_memoryview",
        '}',
        '',
        'def _array_to_list(x):',
        '    if x is None: return None, {}',
        "    return list(x), {'serialization': ('floatList', 'TestWidget')}",
        'def _list_to_array(x):',
        "    return array('d',x)",
        'arrays_list = {',
        "    'from_json': _list_to_array,",
        "    'to_json': _array_to_list",
        '}',
        '',
        'class TestWidget(widgets.DOMWidget):',
        "    _view_module = Unicode('TestWidget', sync=True)",
        "    _view_name = Unicode('TestWidget', sync=True)",
        '    array_binary = Instance(array, sync=True, **arrays_binary)',
        '    array_list = Instance(array, sync=True, **arrays_list)',
        '    msg = {}',
        '    def __init__(self, **kwargs):',
        '        super(widgets.DOMWidget, self).__init__(**kwargs)',
        '        self.on_msg(self._msg)',
        '    def _msg(self, _, content, buffers):',
        '        self.msg = [content, buffers]',
        'x=TestWidget()',
        'display(x)',
        'print x.model_id'].join('\n'), function(index){
            testwidget.index = index;
            testwidget.model_id = this.get_output_cell(index).text.trim();
        });
    this.wait_for_widget(testwidget);

    this.append_cell_execute_then('x.array_list = array("d", [1.5, 2.0, 3.1])');
    this.wait_for_widget(testwidget);
    this.then(function() {
        var result = this.evaluate(function(index) {
            var v = IPython.notebook.get_cell(index).widget_views[0];
            var result = v.model.get('array_list');
            var z = result.slice();
            z[0]+="1234";
            z[1]+="5678";
            v.model.set('array_list', z);
            v.touch();
            return result;
        }, testwidget.index);
        this.test.assertEquals(result, ["1.5", "2", "3.1"], "JSON custom serializer kernel -> js");
    });

    this.assert_output_equals('print x.array_list.tolist() == [1.51234, 25678.0, 3.1]',
                              'True', 'JSON custom serializer js -> kernel');

    if (this.slimerjs) {
        this.append_cell_execute_then("x.array_binary=array('d', [1.5,2.5,5])", function() {
            this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                var z = v.model.get('array_binary');
                z[0]*=3;
                z[1]*=3;
                z[2]*=3;
                // we set to null so that we recognize the change
                // when we set data back to z
                v.model.set('array_binary', null);
                v.model.set('array_binary', z);
                v.touch();
            }, textwidget.index);
        });
        this.wait_for_widget(testwidget);
        this.assert_output_equals('x.array_binary.tolist() == [4.5, 7.5, 15.0]',
                                  'True\n', 'Binary custom serializer js -> kernel')

        this.append_cell_execute_then('x.send("some content", [memoryview(b"binarycontent"), memoryview("morecontent")])');
        this.wait_for_widget(testwidget);

        this.then(function() {
            var result = this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                var d = new TextDecoder('utf-8');
                return {text: v.msg[0],
                        binary0: d.decode(v.msg[1][0]),
                        binary1: d.decode(v.msg[1][1])};
            }, testwidget.index);
            this.test.assertEquals(result, {text: 'some content',
                                       binary0: 'binarycontent',
                                       binary1: 'morecontent'},
                              "Binary widget messages kernel -> js");
        });

        this.then(function() {
            this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                v.send('content back', [new Uint8Array([1,2,3,4]), new Float64Array([2.1828, 3.14159])])
            }, testwidget.index);
        });
        this.wait_for_widget(testwidget);
        this.assert_output_equals([
            'all([x.msg[0] == "content back",',
            '     x.msg[1][0].tolist() == [1,2,3,4],',
            '     array("d", x.msg[1][1].tobytes()).tolist() == [2.1828, 3.14159]])'].join('\n'),
                                  'True', 'Binary buffers message js -> kernel');
    } else {
        console.log("skipping binary websocket tests on phantomjs");
    }

});
<commit_msg>Make quoting consistent in the new tests<commit_after>var xor = function (a, b) {return !a ^ !b;};
var isArray = function (a) {
    try {
        return Object.toString.call(a) === "[object Array]" || Object.toString.call(a) === "[object RuntimeArray]";
    } catch (e) {
        return Array.isArray(a);
    }
};
var recursive_compare = function(a, b) {
    // Recursively compare two objects.
    var same = true;
    same = same && !xor(a instanceof Object || typeof a == 'object', b instanceof Object || typeof b == 'object');
    same = same && !xor(isArray(a), isArray(b));

    if (same) {
        if (a instanceof Object) {
            var key;
            for (key in a) {
                if (a.hasOwnProperty(key) && !recursive_compare(a[key], b[key])) {
                    same = false;
                    break;
                }
            }
            for (key in b) {
                if (b.hasOwnProperty(key) && !recursive_compare(a[key], b[key])) {
                    same = false;
                    break;
                }
            }
        } else {
            return a === b;
        }
    }

    return same;
};

// Test the widget framework.
casper.notebook_test(function () {
    var index;

    index = this.append_cell(
        ['from IPython.html import widgets',
         'from IPython.display import display, clear_output',
         'print("Success")'].join('\n'));
    this.execute_cell_then(index);

    this.then(function () {
        // Test multi-set, single touch code.  First create a custom widget.
        this.thenEvaluate(function() {
            var MultiSetView = IPython.DOMWidgetView.extend({
                render: function(){
                    this.model.set('a', 1);
                    this.model.set('b', 2);
                    this.model.set('c', 3);
                    this.touch();
                },
            });
            IPython.WidgetManager.register_widget_view('MultiSetView', MultiSetView);
        }, {});
    });

    // Try creating the multiset widget, verify that sets the values correctly.
    var multiset = {};
    multiset.index = this.append_cell([
        'from IPython.utils.traitlets import Unicode, CInt',
        'class MultiSetWidget(widgets.Widget):',
        '    _view_name = Unicode("MultiSetView", sync=True)',
        '    a = CInt(0, sync=True)',
        '    b = CInt(0, sync=True)',
        '    c = CInt(0, sync=True)',
        '    d = CInt(-1, sync=True)', // See if it sends a full state.
        '    def set_state(self, sync_data):',
        '        widgets.Widget.set_state(self, sync_data)',
        '        self.d = len(sync_data)',
        'multiset = MultiSetWidget()',
        'display(multiset)',
        'print(multiset.model_id)'].join('\n'));
    this.execute_cell_then(multiset.index, function(index) {
        multiset.model_id = this.get_output_cell(index).text.trim();
    });

    this.wait_for_widget(multiset);

    index = this.append_cell(
        'print("%d%d%d" % (multiset.a, multiset.b, multiset.c))');
    this.execute_cell_then(index, function(index) {
        this.test.assertEquals(this.get_output_cell(index).text.trim(), '123',
            'Multiple model.set calls and one view.touch update state in back-end.');
    });

    index = this.append_cell(
        'print("%d" % (multiset.d))');
    this.execute_cell_then(index, function(index) {
        this.test.assertEquals(this.get_output_cell(index).text.trim(), '3',
            'Multiple model.set calls sent a partial state.');
    });

    var textbox = {};
    throttle_index = this.append_cell([
        'import time',
        'textbox = widgets.Text()',
        'display(textbox)',
        'textbox._dom_classes = ["my-throttle-textbox"]',
        'def handle_change(name, old, new):',
        '    display(len(new))',
        '    time.sleep(0.5)',
        'textbox.on_trait_change(handle_change, "value")',
        'print(textbox.model_id)'].join('\n'));
    this.execute_cell_then(throttle_index, function(index){
        textbox.model_id = this.get_output_cell(index).text.trim();

        this.test.assert(this.cell_element_exists(index,
            '.widget-area .widget-subarea'),
            'Widget subarea exists.');

        this.test.assert(this.cell_element_exists(index,
            '.my-throttle-textbox'), 'Textbox exists.');

        // Send 20 characters
        this.sendKeys('.my-throttle-textbox input', '12345678901234567890');
    });

    this.wait_for_widget(textbox);

    this.then(function () {
        var outputs = this.evaluate(function(i) {
            return IPython.notebook.get_cell(i).output_area.outputs;
        }, {i : throttle_index});

        // Only 4 outputs should have printed, but because of timing, sometimes
        // 5 outputs will print.  All we need to do is verify num outputs <= 5
        // because that is much less than 20.
        this.test.assert(outputs.length <= 5, 'Messages throttled.');

        // We also need to verify that the last state sent was correct.
        var last_state = outputs[outputs.length-1].data['text/plain'];
        this.test.assertEquals(last_state, "20", "Last state sent when throttling.");
    });

    this.thenEvaluate(function() {
        define('TestWidget', ['widgets/js/widget', 'base/js/utils'], function(widget, utils) {
            var TestWidget = widget.DOMWidgetView.extend({
                render: function () {
                    this.listenTo(this.model, 'msg:custom', this.handle_msg);
                },
                handle_msg: function(content, buffers) {
                    this.msg = [content, buffers];
                }
            });

            var floatArray = {
                deserialize: function (value, model) {
                    // DataView -> float64 typed array
                    return new Float64Array(value.buffer);
                },
                // serialization automatically handled by message buffers
            };

            var floatList = {
                deserialize: function (value, model) {
                    // list of floats -> list of strings
                    return value.map(function(x) {return x.toString()});
                },
                serialize: function(value, model) {
                    // list of strings -> list of floats
                    return value.map(function(x) {return parseFloat(x);})
                }
            };
            return {TestWidget: TestWidget, floatArray: floatArray, floatList: floatList};
        });
    });

    var testwidget = {};
    this.append_cell_execute_then([
        'from IPython.html import widgets',
        'from IPython.utils.traitlets import Unicode, Instance, List',
        'from IPython.display import display',
        'from array import array',
        'def _array_to_memoryview(x):',
        '    if x is None: return None, {}',
        '    try:',
        '        y = memoryview(x)',
        '    except TypeError:',
        '        # in python 2, arrays do not support the new buffer protocol',
        '        y = memoryview(buffer(x))',
        '    return y, {"serialization": ("floatArray", "TestWidget")}',
        'def _memoryview_to_array(x):',
        '    return array("d", x.tobytes())',
        'arrays_binary = {',
        '    "from_json": _memoryview_to_array,',
        '    "to_json": _array_to_memoryview',
        '}',
        '',
        'def _array_to_list(x):',
        '    if x is None: return None, {}',
        '    return list(x), {"serialization": ("floatList", "TestWidget")}',
        'def _list_to_array(x):',
        '    return array("d",x)',
        'arrays_list = {',
        '    "from_json": _list_to_array,',
        '    "to_json": _array_to_list',
        '}',
        '',
        'class TestWidget(widgets.DOMWidget):',
        '    _view_module = Unicode("TestWidget", sync=True)',
        '    _view_name = Unicode("TestWidget", sync=True)',
        '    array_binary = Instance(array, sync=True, **arrays_binary)',
        '    array_list = Instance(array, sync=True, **arrays_list)',
        '    msg = {}',
        '    def __init__(self, **kwargs):',
        '        super(widgets.DOMWidget, self).__init__(**kwargs)',
        '        self.on_msg(self._msg)',
        '    def _msg(self, _, content, buffers):',
        '        self.msg = [content, buffers]',
        'x=TestWidget()',
        'display(x)',
        'print x.model_id'].join('\n'), function(index){
            testwidget.index = index;
            testwidget.model_id = this.get_output_cell(index).text.trim();
        });
    this.wait_for_widget(testwidget);

    this.append_cell_execute_then('x.array_list = array("d", [1.5, 2.0, 3.1])');
    this.wait_for_widget(testwidget);
    this.then(function() {
        var result = this.evaluate(function(index) {
            var v = IPython.notebook.get_cell(index).widget_views[0];
            var result = v.model.get('array_list');
            var z = result.slice();
            z[0]+="1234";
            z[1]+="5678";
            v.model.set('array_list', z);
            v.touch();
            return result;
        }, testwidget.index);
        this.test.assertEquals(result, ["1.5", "2", "3.1"], "JSON custom serializer kernel -> js");
    });

    this.assert_output_equals('print x.array_list.tolist() == [1.51234, 25678.0, 3.1]',
                              'True', 'JSON custom serializer js -> kernel');

    if (this.slimerjs) {
        this.append_cell_execute_then("x.array_binary=array('d', [1.5,2.5,5])", function() {
            this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                var z = v.model.get('array_binary');
                z[0]*=3;
                z[1]*=3;
                z[2]*=3;
                // we set to null so that we recognize the change
                // when we set data back to z
                v.model.set('array_binary', null);
                v.model.set('array_binary', z);
                v.touch();
            }, textwidget.index);
        });
        this.wait_for_widget(testwidget);
        this.assert_output_equals('x.array_binary.tolist() == [4.5, 7.5, 15.0]',
                                  'True\n', 'Binary custom serializer js -> kernel')

        this.append_cell_execute_then('x.send("some content", [memoryview(b"binarycontent"), memoryview("morecontent")])');
        this.wait_for_widget(testwidget);

        this.then(function() {
            var result = this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                var d = new TextDecoder('utf-8');
                return {text: v.msg[0],
                        binary0: d.decode(v.msg[1][0]),
                        binary1: d.decode(v.msg[1][1])};
            }, testwidget.index);
            this.test.assertEquals(result, {text: 'some content',
                                       binary0: 'binarycontent',
                                       binary1: 'morecontent'},
                              "Binary widget messages kernel -> js");
        });

        this.then(function() {
            this.evaluate(function(index) {
                var v = IPython.notebook.get_cell(index).widget_views[0];
                v.send('content back', [new Uint8Array([1,2,3,4]), new Float64Array([2.1828, 3.14159])])
            }, testwidget.index);
        });
        this.wait_for_widget(testwidget);
        this.assert_output_equals([
            'all([x.msg[0] == "content back",',
            '     x.msg[1][0].tolist() == [1,2,3,4],',
            '     array("d", x.msg[1][1].tobytes()).tolist() == [2.1828, 3.14159]])'].join('\n'),
                                  'True', 'Binary buffers message js -> kernel');
    } else {
        console.log("skipping binary websocket tests on phantomjs");
    }

});
<|endoftext|>