<commit_before>/**
 * @file Main file for the Memcache Client
 */

var debug = require('debug')('memcache-plus:client');

var _ = require('lodash'),
    assert = require('chai').assert,
    HashRing = require('hashring'),
    misc = require('./misc'),
    Promise = require('bluebird'),
    Queue = require('collections/deque'),
    R = require('ramda');

var Connection = require('./connection');

/**
 * Constructor - Initiate client
 */
function Client(opts) {
    if (!(this instanceof Client)) {
        return new Client(opts);
    }

    var options = {};

    // If single connection provided, array-ify it
    if (typeof opts === 'string') {
        options.hosts = [opts];
        opts = options;
    } else if (typeof opts === 'undefined') {
        opts = {};
    } else if (_.isArray(opts)) {
        options.hosts = opts;
        opts = options;
    }

    _.defaults(opts, {
        autodiscover: false,
        bufferBeforeError: 1000,
        disabled: false,
        hosts: null,
        reconnect: true,
        onNetError: function onNetError(err) { console.error(err); },
        queue: true,
        netTimeout: 500,
        backoffLimit: 10000,
        maxValueSize: 1048576
    });

    // Iterate over options, assign each to this object
    R.keys(opts).forEach(function(key) {
        this[key] = opts[key];
    }, this);

    debug('Connect options', opts);
    this.connect();
}

/**
 * connect() - Iterate over all hosts, connect to each.
 *
 * @api private
 */
Client.prototype.connect = function() {
    debug('starting connection');
    this.connections = {};

    if (this.hosts === null) {
        this.hosts = ['localhost:11211'];
    }

    if (this.autodiscover) {
        // First connect to the servers provided
        this.getHostList()
            .bind(this)
            .then(function() {
                debug('got host list, connecting to hosts');
                // Connect to these hosts
                this.connectToHosts();
                this.ring = new HashRing(_.keys(this.connections));
            });

        // Then get the list of servers

        // Then connect to those
    } else {
        this.connectToHosts();
    }
};

/**
 * disconnect() - Iterate over all hosts, disconnect from each.
 *
 * @api private
 */
Client.prototype.disconnect = function(opts) {
    debug('starting disconnection');
    var connections;

    if (typeof opts === 'string') {
        // If single connection provided, array-ify it
        connections = [opts];
    } else if (typeof opts === 'undefined') {
        // No connections specified so client wants to disconnect from all
        connections = R.keys(this.connections);
    } else if (_.isArray(opts)) {
        connections = opts;
    }

    if (connections.length === R.keys(this.connections).length) {
        // Fair to assume if client is requesting a full disconnect, they don't
        //  want it to just reconnect
        this.reconnect = false;
    }

    connections.map(function(ckey) {
        debug('disconnecting from %s', ckey);
        // Check that host exists before disconnecting from it
        if (this.connections[ckey] === undefined) {
            debug('failure trying to disconnect from server [%s] because not connected', ckey);
            throw new Error('Cannot disconnect from server unless connected');
        }
        this.connections[ckey].disconnect();
        // Remove this connection
        delete this.connections[ckey];

        // Remove this host from the list of hosts
        this.hosts = this.hosts.filter(function(host) {
            return host !== ckey;
        });
    }.bind(this));

    return Promise.resolve(null);
};

/**
 * getHostList() - Given a list of hosts, contact them via Elasticache
 *   autodiscover and retrieve the list of hosts
 *
 * @api private
 */
Client.prototype.getHostList = function() {

    var connections = {};
    // Promise.any because we don't care which completes first, as soon as we get
    // a list of hosts we can stop
    return Promise.any(this.hosts.map(function(host) {
        var h = this.splitHost(host);
        var deferred = misc.defer();
        connections[host] = new Connection({
            host: h.host,
            port: h.port,
            reconnect: false,
            onConnect: function() {
                // Do the autodiscovery, then resolve with hosts
                return deferred.resolve(this.autodiscovery());
            },
            onError: this.onNetError
        });

        return deferred.promise;
    }, this)).bind(this).then(function(hosts) {
        this.hosts = hosts;
        this.connectToHosts();
        this.flushBuffer();
    });
};

/**
 * connectToHosts() - Given a list of hosts, actually connect to them
 *
 * @api private
 */
Client.prototype.connectToHosts = function() {
    debug('connecting to all hosts');
    this.hosts.forEach(function(host) {
        var h = this.splitHost(host);
        var client = this;

        // Connect to host
        this.connections[host] = new Connection({
            host: h.host,
            port: h.port,
            reconnect: this.reconnect,
            onConnect: function() {
                client.flushBuffer();
            },
            bufferBeforeError: this.bufferBeforeError,
            onError: this.onNetError,
            maxValueSize: this.maxValueSize
        });
    }, this);

    this.ring = new HashRing(_.keys(this.connections));
};

/**
 * flushBuffer() - Flush the current buffer of commands, if any
 *
 * @api private
 */
Client.prototype.flushBuffer = function() {
    if (this.buffer && this.buffer.length > 0) {
        debug('flushing client write buffer');
        // @todo Watch out for and handle how this behaves with a very long buffer
        while(this.buffer.length > 0) {
            var item = this.buffer.shift();

            // First, retrieve the correct connection out of the hashring
            var connection = this.connections[this.ring.get(item.key)];

            var promise = connection[item.cmd].apply(connection, item.args);
            promise.then(item.deferred.resolve, item.deferred.reject);
        }
    }
};

/**
 * splitHost() - Helper to split a host string into port and host
 *
 * @api private
 */
Client.prototype.splitHost = function(str) {
    var host = str.split(':');

    if (host.length === 1 && host.indexOf(':') === -1) {
        host.push('11211');
    } else if (host[0].length === 0) {
        host[0] = 'localhost';
    }
    return {
        host: host[0],
        port: host[1]
    };
};

/**
 * ready() - Predicate function, returns true if Client is ready, false otherwise.
 *   Client is ready when all of its connections are open and ready. If autodiscovery
 *   is enabled, Client is ready once it has contacted Elasticache and then initialized
 *   all of the connections
 */
Client.prototype.ready = function() {
    var size = _.size(this.connections);

    if (size < 1) {
        return false;
    } else {
        return _.reduce(this.connections, function(ready, conn) {
            ready = ready && conn.ready;
            return ready;
        }, true);
    }
};

/**
 * delete() - Delete an item from the cache
 *
 * @param {String} key - The key of the item to delete
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.delete = function(key, cb) {
    assert(key, 'Cannot delete without key!');
    return this.run('delete', [key], cb);
};

/**
 * deleteMulti() - Delete multiple items from the cache
 *
 * @param {Array} keys - The keys of the items to delete
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.deleteMulti = function(keys, cb) {
    var self = this;
    assert(keys, 'Cannot delete without keys!');
    return Promise.props(R.reduce(function(acc, key) {
        acc[key] = self.run('delete', [key], null);
        return acc;
    }, {}, keys)).nodeify(cb);
};

/**
 * set() - Set a value for the provided key
 *
 * @param {String} key - The key to set
 * @param {*} value - The value to set for this key. Can be of any type
 * @param {Number|Object|Function} [ttl = 0] - The time to live for this key or callback
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.set = function(key, val, ttl, cb) {
    assert(key, 'Cannot set without key!');

    if (typeof ttl === 'function') {
        cb = ttl;
        ttl = 0;
    }

    return this.run('set', [key, val, ttl], cb);
};

/**
 * get() - Get the value for the provided key
 *
 * @param {String} key - The key to get
 * @param {Object} opts - Any options for this request
 * @param {Function} [cb] - The (optional) callback called on completion
 * @returns {Promise}
 */
Client.prototype.get = function(key, opts, cb) {
    assert(key, 'Cannot get without key!');
    if (typeof opts === 'function' && typeof cb === 'undefined') {
        cb = opts;
        opts = {};
    }

    if (_.isArray(key)) {
        return this.getMulti(key, cb);
    } else {
        return this.run('get', [key, opts], cb);
    }
};

/**
 * getMulti() - Get multiple values for the provided array of keys
 *
 * @param {Array} keys - The keys to get
 * @param {Function} [cb] - The value to set for this key. Can be of any type
 * @returns {Promise}
 */
Client.prototype.getMulti = function(keys, opts, cb) {
    var self = this;
    assert(keys, 'Cannot get without key!');
    if (typeof opts === 'function' && typeof cb === 'undefined') {
        cb = opts;
        opts = {};
    }

    return Promise.props(R.reduce(function(acc, key) {
        acc[key] = self.run('get', [key, opts], null);
        return acc;
    }, {}, keys)).nodeify(cb);
};

/**
 * incr() - Increment a value for the provided key
 *
 * @param {String} key - The key to incr
 * @param {Number|Function} [value = 1] - The value to increment this key by. Must be an integer
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.incr = function(key, val, cb) {
    assert(key, 'Cannot incr without key!');

    if (typeof val === 'function' || typeof val === 'undefined') {
        cb = val;
        val = 1;
    }

    return this.run('incr', [key, val], cb);
};

/**
 * decr() - Decrement a value for the provided key
 *
 * @param {String} key - The key to decr
 * @param {Number|Function} [value = 1] - The value to decrement this key by. Must be an integer
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.decr = function(key, val, cb) {
    assert(key, 'Cannot decr without key!');

    if (typeof val === 'function' || typeof val === 'undefined') {
        cb = val;
        val = 1;
    }

    return this.run('decr', [key, val], cb);
};

/**
 * run() - Run this command on the appropriate connection. Will buffer command
 *   if connection(s) are not ready
 *
 * @param {String} command - The command to run
 * @param {Array} args - The arguments to send with this command
 * @returns {Promise}
 */
Client.prototype.run = function(command, args, cb) {
    if (this.disabled) {
        return Promise.resolve(null).nodeify(cb);
    }

    if (this.ready()) {
        // First, retrieve the correct connection out of the hashring
        var connection = this.connections[this.ring.get(args[0])];

        // Run this command
        return connection[command].apply(connection, args).nodeify(cb);
    } else if (this.bufferBeforeError === 0) {
        return Promise.reject('Connection is not ready, either not connected yet or disconnected').nodeify(cb);
    }

    // @todo remove this?
    if (this.queue) {
        var deferred = misc.defer(args[0]);

        this.buffer = this.buffer || new Queue();

        this.buffer.push({
            cmd: command,
            args: args,
            key: args[0],
            deferred: deferred
        });

        return deferred.promise.nodeify(cb);
    }

    return Promise.resolve(null).nodeify(cb);
};

module.exports = Client;
<commit_msg>Wrap error message in actual error<commit_after>/**
 * @file Main file for the Memcache Client
 */

var debug = require('debug')('memcache-plus:client');

var _ = require('lodash'),
    assert = require('chai').assert,
    HashRing = require('hashring'),
    misc = require('./misc'),
    Promise = require('bluebird'),
    Queue = require('collections/deque'),
    R = require('ramda');

var Connection = require('./connection');

/**
 * Constructor - Initiate client
 */
function Client(opts) {
    if (!(this instanceof Client)) {
        return new Client(opts);
    }

    var options = {};

    // If single connection provided, array-ify it
    if (typeof opts === 'string') {
        options.hosts = [opts];
        opts = options;
    } else if (typeof opts === 'undefined') {
        opts = {};
    } else if (_.isArray(opts)) {
        options.hosts = opts;
        opts = options;
    }

    _.defaults(opts, {
        autodiscover: false,
        bufferBeforeError: 1000,
        disabled: false,
        hosts: null,
        reconnect: true,
        onNetError: function onNetError(err) { console.error(err); },
        queue: true,
        netTimeout: 500,
        backoffLimit: 10000,
        maxValueSize: 1048576
    });

    // Iterate over options, assign each to this object
    R.keys(opts).forEach(function(key) {
        this[key] = opts[key];
    }, this);

    debug('Connect options', opts);
    this.connect();
}

/**
 * connect() - Iterate over all hosts, connect to each.
 *
 * @api private
 */
Client.prototype.connect = function() {
    debug('starting connection');
    this.connections = {};

    if (this.hosts === null) {
        this.hosts = ['localhost:11211'];
    }

    if (this.autodiscover) {
        // First connect to the servers provided
        this.getHostList()
            .bind(this)
            .then(function() {
                debug('got host list, connecting to hosts');
                // Connect to these hosts
                this.connectToHosts();
                this.ring = new HashRing(_.keys(this.connections));
            });

        // Then get the list of servers

        // Then connect to those
    } else {
        this.connectToHosts();
    }
};

/**
 * disconnect() - Iterate over all hosts, disconnect from each.
 *
 * @api private
 */
Client.prototype.disconnect = function(opts) {
    debug('starting disconnection');
    var connections;

    if (typeof opts === 'string') {
        // If single connection provided, array-ify it
        connections = [opts];
    } else if (typeof opts === 'undefined') {
        // No connections specified so client wants to disconnect from all
        connections = R.keys(this.connections);
    } else if (_.isArray(opts)) {
        connections = opts;
    }

    if (connections.length === R.keys(this.connections).length) {
        // Fair to assume if client is requesting a full disconnect, they don't
        //  want it to just reconnect
        this.reconnect = false;
    }

    connections.map(function(ckey) {
        debug('disconnecting from %s', ckey);
        // Check that host exists before disconnecting from it
        if (this.connections[ckey] === undefined) {
            debug('failure trying to disconnect from server [%s] because not connected', ckey);
            throw new Error('Cannot disconnect from server unless connected');
        }
        this.connections[ckey].disconnect();
        // Remove this connection
        delete this.connections[ckey];

        // Remove this host from the list of hosts
        this.hosts = this.hosts.filter(function(host) {
            return host !== ckey;
        });
    }.bind(this));

    return Promise.resolve(null);
};

/**
 * getHostList() - Given a list of hosts, contact them via Elasticache
 *   autodiscover and retrieve the list of hosts
 *
 * @api private
 */
Client.prototype.getHostList = function() {

    var connections = {};
    // Promise.any because we don't care which completes first, as soon as we get
    // a list of hosts we can stop
    return Promise.any(this.hosts.map(function(host) {
        var h = this.splitHost(host);
        var deferred = misc.defer();
        connections[host] = new Connection({
            host: h.host,
            port: h.port,
            reconnect: false,
            onConnect: function() {
                // Do the autodiscovery, then resolve with hosts
                return deferred.resolve(this.autodiscovery());
            },
            onError: this.onNetError
        });

        return deferred.promise;
    }, this)).bind(this).then(function(hosts) {
        this.hosts = hosts;
        this.connectToHosts();
        this.flushBuffer();
    });
};

/**
 * connectToHosts() - Given a list of hosts, actually connect to them
 *
 * @api private
 */
Client.prototype.connectToHosts = function() {
    debug('connecting to all hosts');
    this.hosts.forEach(function(host) {
        var h = this.splitHost(host);
        var client = this;

        // Connect to host
        this.connections[host] = new Connection({
            host: h.host,
            port: h.port,
            reconnect: this.reconnect,
            onConnect: function() {
                client.flushBuffer();
            },
            bufferBeforeError: this.bufferBeforeError,
            onError: this.onNetError,
            maxValueSize: this.maxValueSize
        });
    }, this);

    this.ring = new HashRing(_.keys(this.connections));
};

/**
 * flushBuffer() - Flush the current buffer of commands, if any
 *
 * @api private
 */
Client.prototype.flushBuffer = function() {
    if (this.buffer && this.buffer.length > 0) {
        debug('flushing client write buffer');
        // @todo Watch out for and handle how this behaves with a very long buffer
        while(this.buffer.length > 0) {
            var item = this.buffer.shift();

            // First, retrieve the correct connection out of the hashring
            var connection = this.connections[this.ring.get(item.key)];

            var promise = connection[item.cmd].apply(connection, item.args);
            promise.then(item.deferred.resolve, item.deferred.reject);
        }
    }
};

/**
 * splitHost() - Helper to split a host string into port and host
 *
 * @api private
 */
Client.prototype.splitHost = function(str) {
    var host = str.split(':');

    if (host.length === 1 && host.indexOf(':') === -1) {
        host.push('11211');
    } else if (host[0].length === 0) {
        host[0] = 'localhost';
    }
    return {
        host: host[0],
        port: host[1]
    };
};

/**
 * ready() - Predicate function, returns true if Client is ready, false otherwise.
 *   Client is ready when all of its connections are open and ready. If autodiscovery
 *   is enabled, Client is ready once it has contacted Elasticache and then initialized
 *   all of the connections
 */
Client.prototype.ready = function() {
    var size = _.size(this.connections);

    if (size < 1) {
        return false;
    } else {
        return _.reduce(this.connections, function(ready, conn) {
            ready = ready && conn.ready;
            return ready;
        }, true);
    }
};

/**
 * delete() - Delete an item from the cache
 *
 * @param {String} key - The key of the item to delete
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.delete = function(key, cb) {
    assert(key, 'Cannot delete without key!');
    return this.run('delete', [key], cb);
};

/**
 * deleteMulti() - Delete multiple items from the cache
 *
 * @param {Array} keys - The keys of the items to delete
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.deleteMulti = function(keys, cb) {
    var self = this;
    assert(keys, 'Cannot delete without keys!');
    return Promise.props(R.reduce(function(acc, key) {
        acc[key] = self.run('delete', [key], null);
        return acc;
    }, {}, keys)).nodeify(cb);
};

/**
 * set() - Set a value for the provided key
 *
 * @param {String} key - The key to set
 * @param {*} value - The value to set for this key. Can be of any type
 * @param {Number|Object|Function} [ttl = 0] - The time to live for this key or callback
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.set = function(key, val, ttl, cb) {
    assert(key, 'Cannot set without key!');

    if (typeof ttl === 'function') {
        cb = ttl;
        ttl = 0;
    }

    return this.run('set', [key, val, ttl], cb);
};

/**
 * get() - Get the value for the provided key
 *
 * @param {String} key - The key to get
 * @param {Object} opts - Any options for this request
 * @param {Function} [cb] - The (optional) callback called on completion
 * @returns {Promise}
 */
Client.prototype.get = function(key, opts, cb) {
    assert(key, 'Cannot get without key!');
    if (typeof opts === 'function' && typeof cb === 'undefined') {
        cb = opts;
        opts = {};
    }

    if (_.isArray(key)) {
        return this.getMulti(key, cb);
    } else {
        return this.run('get', [key, opts], cb);
    }
};

/**
 * getMulti() - Get multiple values for the provided array of keys
 *
 * @param {Array} keys - The keys to get
 * @param {Function} [cb] - The value to set for this key. Can be of any type
 * @returns {Promise}
 */
Client.prototype.getMulti = function(keys, opts, cb) {
    var self = this;
    assert(keys, 'Cannot get without key!');
    if (typeof opts === 'function' && typeof cb === 'undefined') {
        cb = opts;
        opts = {};
    }

    return Promise.props(R.reduce(function(acc, key) {
        acc[key] = self.run('get', [key, opts], null);
        return acc;
    }, {}, keys)).nodeify(cb);
};

/**
 * incr() - Increment a value for the provided key
 *
 * @param {String} key - The key to incr
 * @param {Number|Function} [value = 1] - The value to increment this key by. Must be an integer
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.incr = function(key, val, cb) {
    assert(key, 'Cannot incr without key!');

    if (typeof val === 'function' || typeof val === 'undefined') {
        cb = val;
        val = 1;
    }

    return this.run('incr', [key, val], cb);
};

/**
 * decr() - Decrement a value for the provided key
 *
 * @param {String} key - The key to decr
 * @param {Number|Function} [value = 1] - The value to decrement this key by. Must be an integer
 * @param {Function} [cb] - Callback to call when we have a value
 * @returns {Promise}
 */
Client.prototype.decr = function(key, val, cb) {
    assert(key, 'Cannot decr without key!');

    if (typeof val === 'function' || typeof val === 'undefined') {
        cb = val;
        val = 1;
    }

    return this.run('decr', [key, val], cb);
};

/**
 * run() - Run this command on the appropriate connection. Will buffer command
 *   if connection(s) are not ready
 *
 * @param {String} command - The command to run
 * @param {Array} args - The arguments to send with this command
 * @returns {Promise}
 */
Client.prototype.run = function(command, args, cb) {
    if (this.disabled) {
        return Promise.resolve(null).nodeify(cb);
    }

    if (this.ready()) {
        // First, retrieve the correct connection out of the hashring
        var connection = this.connections[this.ring.get(args[0])];

        // Run this command
        return connection[command].apply(connection, args).nodeify(cb);
    } else if (this.bufferBeforeError === 0) {
        return Promise.reject(new Error('Connection is not ready, either not connected yet or disconnected')).nodeify(cb);
    }

    // @todo remove this?
    if (this.queue) {
        var deferred = misc.defer(args[0]);

        this.buffer = this.buffer || new Queue();

        this.buffer.push({
            cmd: command,
            args: args,
            key: args[0],
            deferred: deferred
        });

        return deferred.promise.nodeify(cb);
    }

    return Promise.resolve(null).nodeify(cb);
};

module.exports = Client;
<|endoftext|>


<commit_before>import urls from '../../../../../src/lib/urls'

const searchEndpoint = '/api-proxy/v3/search/event'

describe('Event Collections Sort', () => {
  context('Default sort', () => {
    before(() => {
      cy.intercept('POST', searchEndpoint).as('apiRequest')
      cy.visit(urls.events.react.index())
    })

    it('should apply the default sort', () => {
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:desc')
      })
    })

    it('should have all sort options', () => {
      cy.get('[data-test="sortby"] option').then((options) => {
        const sortOptions = [...options].map((o) => [o.value, o.text])
        expect(sortOptions).to.deep.eq([
          ['name:asc', 'Event name A-Z'],
          ['modified_on:desc', 'Recently updated'],
          ['modified_on:asc', 'Least recently updated'],
          ['start_date:asc', 'Earliest start date'],
          ['start_date:desc', 'Latest start date'],
        ])
      })
    })
  })

  context('User sort', () => {
    const element = '[data-test="sortby"] select'

    beforeEach(() => {
      cy.intercept('POST', searchEndpoint).as('apiRequest')
      cy.visit(urls.events.react.index())
      cy.wait('@apiRequest')
    })

    it('should sort by "Event name A-Z"', () => {
      cy.get(element).select('name:asc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('name:asc')
      })
    })

    it('should sort by "Recently updated"', () => {
      cy.get(element).select('modified_on:desc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:desc')
      })
    })

    it('should sort by "Least recently updated"', () => {
      cy.get(element).select('modified_on:asc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:asc')
      })
    })

    it('should sort by "Earliest start date"', () => {
      cy.get(element).select('start_date:asc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('start_date:asc')
      })
    })

    it('should sort by "Latest start date"', () => {
      cy.get(element).select('start_date:desc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('start_date:desc')
      })
    })
  })
})
<commit_msg>Fix event sort tests<commit_after>import urls from '../../../../../src/lib/urls'

const searchEndpoint = '/api-proxy/v3/search/event'

describe('Event Collections Sort', () => {
  context('Default sort', () => {
    before(() => {
      cy.intercept('POST', searchEndpoint).as('apiRequest')
      cy.visit(urls.events.react.index())
    })

    it('should apply the default sort', () => {
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:desc')
      })
    })

    it('should have all sort options', () => {
      cy.get('[data-test="sortby"] option').then((options) => {
        const sortOptions = [...options].map((o) => [o.value, o.text])
        expect(sortOptions).to.deep.eq([
          ['name:asc', 'Event name A-Z'],
          ['modified_on:desc', 'Recently updated'],
          ['modified_on:asc', 'Least recently updated'],
          ['start_date:asc', 'Earliest start date'],
          ['start_date:desc', 'Latest start date'],
        ])
      })
    })
  })

  context('User sort', () => {
    const element = '[data-test="sortby"] select'

    beforeEach(() => {
      cy.intercept('POST', searchEndpoint).as('apiRequest')
      cy.visit(urls.events.react.index())
      cy.wait('@apiRequest')
    })

    it('should sort by "Event name A-Z"', () => {
      cy.get(element).select('name:asc')
      cy.wait('@apiRequest')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('name:asc')
      })
    })

    it('should sort by "Recently updated"', () => {
      cy.get(element).select('modified_on:desc')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:desc')
      })
    })

    it('should sort by "Least recently updated"', () => {
      cy.get(element).select('modified_on:asc')
      cy.wait('@apiRequest')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('modified_on:asc')
      })
    })

    it('should sort by "Earliest start date"', () => {
      cy.get(element).select('start_date:asc')
      cy.wait('@apiRequest')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('start_date:asc')
      })
    })

    it('should sort by "Latest start date"', () => {
      cy.get(element).select('start_date:desc')
      cy.wait('@apiRequest')
      cy.wait('@apiRequest').then(({ request }) => {
        expect(request.body.sortby).to.equal('start_date:desc')
      })
    })
  })
})
<|endoftext|>


<commit_before>
var getTime = require('../medtronic-clock');

function bgTargetsLookup (inputs) {
  return bound_target_range(lookup(inputs));
}

function lookup (inputs) {
    var bgtargets_data = inputs.targets;
    var temptargets_data = inputs.temptargets;
    var now = new Date();

    //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset });

    var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1];

    for (var i = 0; i < bgtargets_data.targets.length - 1; i++) {
        if ((now >= getTime(bgtargets_data.targets[i].offset)) && (now < getTime(bgtargets_data.targets[i + 1].offset))) {
            bgTargets = bgtargets_data.targets[i];
            break;
        }
    }

    //console.error(temptargets_data);
    //console.error(now);
    for (var i = 0; i < temptargets_data.length; i++) {
        start = new Date(temptargets_data[i].created_at);
        //console.error(start);
        expires = new Date(start.getTime() + temptargets_data[i].duration * 60 * 1000);
        //console.error(expires);
        if (now >= new Date(temptargets_data[i].created_at) && now < expires ) {
            console.error(temptargets_data[i]);
            bgTargets.high = temptargets_data[i].targetTop;
            bgTargets.low = temptargets_data[i].targetBottom;
            //break;
        }
    }
    //console.error(bgTargets);

    return bgTargets;
}

function bound_target_range (target) {
    // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong
    target.max_bg = Math.max(80, target.high);
    target.min_bg = Math.max(80, target.low);
    // hard-code upper bound for min_bg in case pump is set too high
    target.min_bg = Math.min(200, target.min_bg);
    return target
}

bgTargetsLookup.bgTargetsLookup = bgTargetsLookup;
bgTargetsLookup.lookup = lookup;
bgTargetsLookup.bound_target_range = bound_target_range;
exports = module.exports = bgTargetsLookup;

<commit_msg>turn off debugging<commit_after>
var getTime = require('../medtronic-clock');

function bgTargetsLookup (inputs) {
  return bound_target_range(lookup(inputs));
}

function lookup (inputs) {
    var bgtargets_data = inputs.targets;
    var temptargets_data = inputs.temptargets;
    var now = new Date();

    //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset });

    var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1];

    for (var i = 0; i < bgtargets_data.targets.length - 1; i++) {
        if ((now >= getTime(bgtargets_data.targets[i].offset)) && (now < getTime(bgtargets_data.targets[i + 1].offset))) {
            bgTargets = bgtargets_data.targets[i];
            break;
        }
    }

    //console.error(temptargets_data);
    //console.error(now);
    for (var i = 0; i < temptargets_data.length; i++) {
        start = new Date(temptargets_data[i].created_at);
        //console.error(start);
        expires = new Date(start.getTime() + temptargets_data[i].duration * 60 * 1000);
        //console.error(expires);
        if (now >= new Date(temptargets_data[i].created_at) && now < expires ) {
            //console.error(temptargets_data[i]);
            bgTargets.high = temptargets_data[i].targetTop;
            bgTargets.low = temptargets_data[i].targetBottom;
            //break;
        }
    }
    //console.error(bgTargets);

    return bgTargets;
}

function bound_target_range (target) {
    // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong
    target.max_bg = Math.max(80, target.high);
    target.min_bg = Math.max(80, target.low);
    // hard-code upper bound for min_bg in case pump is set too high
    target.min_bg = Math.min(200, target.min_bg);
    return target
}

bgTargetsLookup.bgTargetsLookup = bgTargetsLookup;
bgTargetsLookup.lookup = lookup;
bgTargetsLookup.bound_target_range = bound_target_range;
exports = module.exports = bgTargetsLookup;

<|endoftext|>


<commit_before>/*global window, console, navigator*/

var Erizo = Erizo || {};

Erizo.sessionId = 103;

Erizo.Connection = function (spec) {
    "use strict";
    var that = {};

    spec.session_id = (Erizo.sessionId += 1);

    // Check which WebRTC Stack is installed.
    that.browser = "";

    if (typeof module !== 'undefined' && module.exports) {
        L.Logger.error('Publish/subscribe video/audio streams not supported in erizofc yet');
        that = Erizo.FcStack(spec);
    } else if (window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "23" ||
               window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "24") {
        // Google Chrome Stable.
        console.log("Stable!");
        that = Erizo.ChromeStableStack(spec);
        that.browser = "chrome-stable";
    } else if (window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "25" ||
               window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "26") {
        // Google Chrome Canary.
        console.log("Canary!");
        that = Erizo.ChromeCanaryStack(spec);
        that.browser = "chrome-canary";
    } else if (window.navigator.appVersion.match(/Bowser\/([\w\W]*?)\./)[1] === "25") {
        // Bowser
        that.browser = "bowser";
    } else if (window.navigator.appVersion.match(/Mozilla\/([\w\W]*?)\./)[1] === "25") {
        // Firefox
        that.browser = "mozilla";
    } else {
        // None.
        that.browser = "none";
        throw "WebRTC stack not available";
    }

    return that;
};

Erizo.GetUserMedia = function (config, callback) {
    "use strict";

    if (typeof module !== 'undefined' && module.exports) {
        L.Logger.error('Video/audio streams not supported in erizofc yet');
    } else {
        try {
            navigator.webkitGetUserMedia("audio, video", callback);
            console.log('GetUserMedia BOWSER');
        } catch (e) {
            navigator.webkitGetUserMedia(config, callback);
            console.log('GetUserMedia CHROME');
        }
    }

};
<commit_msg>Updated Canary version<commit_after>/*global window, console, navigator*/

var Erizo = Erizo || {};

Erizo.sessionId = 103;

Erizo.Connection = function (spec) {
    "use strict";
    var that = {};

    spec.session_id = (Erizo.sessionId += 1);

    // Check which WebRTC Stack is installed.
    that.browser = "";

    if (typeof module !== 'undefined' && module.exports) {
        L.Logger.error('Publish/subscribe video/audio streams not supported in erizofc yet');
        that = Erizo.FcStack(spec);
    } else if (window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "23" ||
               window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "24") {
        // Google Chrome Stable.
        console.log("Stable!");
        that = Erizo.ChromeStableStack(spec);
        that.browser = "chrome-stable";
    } else if (window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "26" ||
               window.navigator.appVersion.match(/Chrome\/([\w\W]*?)\./)[1] === "27") {
        // Google Chrome Canary.
        console.log("Canary!");
        that = Erizo.ChromeCanaryStack(spec);
        that.browser = "chrome-canary";
    } else if (window.navigator.appVersion.match(/Bowser\/([\w\W]*?)\./)[1] === "25") {
        // Bowser
        that.browser = "bowser";
    } else if (window.navigator.appVersion.match(/Mozilla\/([\w\W]*?)\./)[1] === "25") {
        // Firefox
        that.browser = "mozilla";
    } else {
        // None.
        that.browser = "none";
        throw "WebRTC stack not available";
    }

    return that;
};

Erizo.GetUserMedia = function (config, callback) {
    "use strict";

    if (typeof module !== 'undefined' && module.exports) {
        L.Logger.error('Video/audio streams not supported in erizofc yet');
    } else {
        try {
            navigator.webkitGetUserMedia("audio, video", callback);
            console.log('GetUserMedia BOWSER');
        } catch (e) {
            navigator.webkitGetUserMedia(config, callback);
            console.log('GetUserMedia CHROME');
        }
    }

};
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { observer } from 'mobx-react';
import { action, computed } from 'mobx';
import { Button } from 'react-bootstrap';
import moment from 'moment';
import { autobind } from 'core-decorators';
import CopyOnFocusInput from './copy-on-focus-input';
import { Icon } from 'shared';
import { compact } from 'lodash';
import Courses from '../models/courses-map';
import TeacherTaskPlan from '../models/task-plans/teacher/plan';
import styled from 'styled-components';

const DUE_FORMAT = 'M/D/YYYY [at] h:mma';

const BackLinkButton = styled(Button)`
  margin: 10px 0 20px 0;
  padding-left: 0 !important;
  font-size: 16px;
`;

const BackLink = (props) => (
  <BackLinkButton variant="link" {...props}>
    <Icon type="chevron-left" /> Back
  </BackLinkButton>
);

export default
@observer
class LmsInfoCard extends React.Component {

  static propTypes = {
    courseId: PropTypes.string.isRequired,
    plan: PropTypes.instanceOf(TeacherTaskPlan).isRequired,
    onBack: PropTypes.func.isRequired,
  }

  @action.bound
  focusInput() {
    this.refs.input.focus();
  }

  @action.bound
  closePopOver() {
    this.refs.overlay.hide();
  }

  @autobind
  renderDueDates() {
    const { plan } = this.props;
    if (plan.areTaskingDatesSame) {
      return (
        <CopyOnFocusInput
          label="Due date"
          value={moment(plan.dateRanges.due.start).format(DUE_FORMAT)}
        />
      );
    }
    const course = Courses.get(this.props.courseId);
    const periodDates = compact(course.periods.map(period => {
      const tp = plan.tasking_plans.forPeriod(period);
      return tp && (
        <CopyOnFocusInput
          label={period.name}
          value={moment(tp.due_at).format(DUE_FORMAT)}
        />);
    }));
    return (

Due dates:

          {periodDates}

    );
  }

  @computed get url() {
    const l = window.location;
    const { shareable_url } = this.props.plan.analytics;
    return shareable_url ? `${l.protocol}//${l.host}${shareable_url}` : '';
  }

  @computed get isPreview() {
    return Courses.get(this.props.courseId).is_preview;
  }

  @computed get popOverBody() {
    if (this.isPreview || !this.url) {
      return (

          {this.props.plan.title}
          {this.renderDueDates()}
          {this.popoverDescription}

      );
    }
    return (

        <CopyOnFocusInput value={this.url} ref="input" readOnly={true} />
        {this.props.plan.title}
        {this.renderDueDates()}
        {this.popoverDescription}

    );
  }

  renderPreview() {
    return (

        <BackLink onClick={this.props.onBack} />

          Assignment links are not available in preview courses. In
          a live course, you can send assignment links directly
          to your students or manually paste them into your
          learning management system.

    );
  }

  render() {
    if (this.isPreview) {
      return this.renderPreview();
    }
    return (

        <BackLink onClick={this.props.onBack} />

          Copy and send to your students directly, or paste manually into your LMS.

        <CopyOnFocusInput label="Assignment URL" value={this.url} />
        {this.renderDueDates()}

    );
  }
}
<commit_msg>add key when mapping CopyOnFocusInput<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { observer } from 'mobx-react';
import { action, computed } from 'mobx';
import { Button } from 'react-bootstrap';
import moment from 'moment';
import { autobind } from 'core-decorators';
import CopyOnFocusInput from './copy-on-focus-input';
import { Icon } from 'shared';
import { compact } from 'lodash';
import Courses from '../models/courses-map';
import TeacherTaskPlan from '../models/task-plans/teacher/plan';
import styled from 'styled-components';

const DUE_FORMAT = 'M/D/YYYY [at] h:mma';

const BackLinkButton = styled(Button)`
  margin: 10px 0 20px 0;
  padding-left: 0 !important;
  font-size: 16px;
`;

const BackLink = (props) => (
  <BackLinkButton variant="link" {...props}>
    <Icon type="chevron-left" /> Back
  </BackLinkButton>
);

export default
@observer
class LmsInfoCard extends React.Component {

  static propTypes = {
    courseId: PropTypes.string.isRequired,
    plan: PropTypes.instanceOf(TeacherTaskPlan).isRequired,
    onBack: PropTypes.func.isRequired,
  }

  @action.bound
  focusInput() {
    this.refs.input.focus();
  }

  @action.bound
  closePopOver() {
    this.refs.overlay.hide();
  }

  @autobind
  renderDueDates() {
    const { plan } = this.props;
    if (plan.areTaskingDatesSame) {
      return (
        <CopyOnFocusInput
          label="Due date"
          value={moment(plan.dateRanges.due.start).format(DUE_FORMAT)}
        />
      );
    }
    const course = Courses.get(this.props.courseId);
    const periodDates = compact(course.periods.map(period => {
      const tp = plan.tasking_plans.forPeriod(period);
      return tp && (
        <CopyOnFocusInput
          label={period.name}
          value={moment(tp.due_at).format(DUE_FORMAT)}
          key={period.id}
        />);
    }));
    return (

Due dates:

          {periodDates}

    );
  }

  @computed get url() {
    const l = window.location;
    const { shareable_url } = this.props.plan.analytics;
    return shareable_url ? `${l.protocol}//${l.host}${shareable_url}` : '';
  }

  @computed get isPreview() {
    return Courses.get(this.props.courseId).is_preview;
  }

  @computed get popOverBody() {
    if (this.isPreview || !this.url) {
      return (

          {this.props.plan.title}
          {this.renderDueDates()}
          {this.popoverDescription}

      );
    }
    return (

        <CopyOnFocusInput value={this.url} ref="input" readOnly={true} />
        {this.props.plan.title}
        {this.renderDueDates()}
        {this.popoverDescription}

    );
  }

  renderPreview() {
    return (

        <BackLink onClick={this.props.onBack} />

          Assignment links are not available in preview courses. In
          a live course, you can send assignment links directly
          to your students or manually paste them into your
          learning management system.

    );
  }

  render() {
    if (this.isPreview) {
      return this.renderPreview();
    }
    return (

        <BackLink onClick={this.props.onBack} />

          Copy and send to your students directly, or paste manually into your LMS.

        <CopyOnFocusInput label="Assignment URL" value={this.url} />
        {this.renderDueDates()}

    );
  }
}
<|endoftext|>


<commit_before>define(['jquery', 'underscore'], function($, _){

	var SELECTOR = '.lwrapper';

	// This template will dump out something like:
	//
 Avg. Rent

	//   $265 - $756
	//   $756 - $1000
	// ...
	var TEMPLATE = '
 <%= title %>
'+
									'<% _.each( data, function(entry){ %>'+
									'<i style="background: <%= entry.color %>;">'+
									'<%= entry.unit %> <%= entry.min %> - '+
									'<%= entry.unit %>  <%= entry.max %> '+
									'
'+
									'<% }) %>';

	// Legend Data is an object with a title attribute, and a data attribute which is an array of legend entries as follows:

	// [
	// 		{
	//		min: <integer>,
	//		max: <integer>,
	//		unit: <string>,
	//		color: <colorHEX>
	// 		},
	//    ...
	// ]
	function render(event, legendData){
		var $el = $(SELECTOR);
		$el.html( _.template(TEMPLATE, legendData));

	}

	function init () {
		// do anything if we need to

		// listen for when there is data, then render
		$(document).on('legend:render', render);

	}

	return {
		init: init
	}

});
<commit_msg>Correction on legend to support formatting with braces<commit_after>define(['jquery', 'underscore'], function($, _){

	var SELECTOR = '.lwrapper';

	// This template will dump out something like:
	//
 Avg. Rent

	//   $265 - $756
	//   $756 - $1000
	// ...
	var TEMPLATE = '
 <%= title %>
'+
									'<% _.each( data, function(entry){ %>'+
									'<i style="background: <%= entry.color %>;">'+
									'<%= entry.unit.replace("{0}",entry.min) %> - '+
									'<%= entry.unit.replace("{0}",entry.max) %>  '+
									'
'+
									'<% }) %>';

	// Legend Data is an object with a title attribute, and a data attribute which is an array of legend entries as follows:

	// [
	// 		{
	//		min: <integer>,
	//		max: <integer>,
	//		unit: <string>,
	//		color: <colorHEX>
	// 		},
	//    ...
	// ]
	function render(event, legendData){
		var $el = $(SELECTOR);
		$el.html( _.template(TEMPLATE, legendData));

	}

	function init () {
		// do anything if we need to

		// listen for when there is data, then render
		$(document).on('legend:render', render);

	}

	return {
		init: init
	}

});
<|endoftext|>


<commit_before>//! moment-holiday.js locale configuration
//! locale : India

(function() {
  var moment = (typeof require !== 'undefined' && require !== null) && !require.amd ? require('moment') : this.moment;

  moment.holidays.croatia = {
    "New Year's Day": {
      date: '1/1',
      keywords: ['naya', 'saal', 'new', 'year']
    },
    "Republic Day": {
      date: '1/26',
      keywords: ['ganatantr divas', 'republic', 'day']
    },
    "Mahavir Jayanti": {
      date: '4/9',
      keywords: ['mahavir', 'birthday']
    },
    "Good Friday": {
      date: 'goodfriday',
      keywords: ['good', 'friday']
    },
    "May Day": {
      date: '5/1',
      keywords: ['may', 'labours', 'day']
    },
    "Independence Day": {
      date: '8/15',
      keywords: ['independence', 'day', 'svatantrata divas']
    },
    "Gandhi Jayanti": {
      date: '10/02',
      keywords: ['gandhi', 'birthday']
    },
    "Christmas Day": {
      date: '12/25',
      keywords: ['christ', 'christmas']
    }
  };

  if ((typeof module !== 'undefined' && module !== null ? module.exports : void 0) != null) { module.exports = moment; }
}).call(this);<commit_msg>edit error locale name, remove good friday<commit_after>//! moment-holiday.js locale configuration
//! locale : India

(function() {
  var moment = (typeof require !== 'undefined' && require !== null) && !require.amd ? require('moment') : this.moment;

  moment.holidays.india = {
    "New Year's Day": {
      date: '1/1',
      keywords: ['naya', 'saal', 'new', 'year']
    },
    "Republic Day": {
      date: '1/26',
      keywords: ['ganatantr divas', 'republic', 'day']
    },
    "Mahavir Jayanti": {
      date: '4/9',
      keywords: ['mahavir', 'birthday']
    },
    "May Day": {
      date: '5/1',
      keywords: ['may', 'labours', 'day']
    },
    "Independence Day": {
      date: '8/15',
      keywords: ['independence', 'day', 'svatantrata divas']
    },
    "Gandhi Jayanti": {
      date: '10/02',
      keywords: ['gandhi', 'birthday']
    },
    "Christmas Day": {
      date: '12/25',
      keywords: ['christ', 'christmas']
    }
  };

  if ((typeof module !== 'undefined' && module !== null ? module.exports : void 0) != null) { module.exports = moment; }
}).call(this);
<|endoftext|>


<commit_before>'use strict'

const westfield = require('westfield-runtime-client')
const session = require('./protocol/session-client-protocol')
const WebSocket = require('ws')

const ShimGlobal = require('./ShimGlobal')
const LocalClient = require('./LocalClient')

module.exports = class LocalSession {
  /**
   * @param request http ws upgrade request
   * @param socket http socket
   * @param head http head
   * @param wlDisplay
   * @returns {Promise<LocalSession>}
   */
  static create (request, socket, head, wlDisplay) {
    const wss = new WebSocket.Server({
      noServer: true
      // path: '/greenfield'
    })
    return new LocalSession(wss, wlDisplay)._handleUpgrade(request, socket, head)
  }

  _handleUpgrade (request, socket, head) {
    return new Promise((resolve) => {
      this._wss.handleUpgrade(request, socket, head, (ws) => {
        const wfcConnection = new westfield.Connection()

        wfcConnection.onSend = (data) => {
          if (ws.readyState === WebSocket.OPEN) {
            try {
              ws.send(data, (error) => {
                if (error !== undefined) {
                  console.error(error)
                  ws.close()
                }
              })
            } catch (error) {
              console.error(error)
              ws.close()
            }
          }
        }

        ws.onmessage = (event) => {
          if (ws.readyState === WebSocket.OPEN) {
            try {
              const b = event.data
              const arrayBuffer = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength)
              wfcConnection.unmarshall(arrayBuffer)
            } catch (error) {
              console.error(error)
              ws.close()
            }
          }
        }

        ws.on('close', () => wfcConnection.close())
        wfcConnection.onClose().then(() => ws.close()).catch((error) => console.log(error))

        // TODO listen for error

        if (this.primaryConnection) {
          const resolve = this.connectionPromises.shift()
          const wlClient = resolve._wlClient
          delete resolve._wlClient
          const localClient = LocalClient.create(wfcConnection, wlClient)
          // TODO destroy proxy once wayland or greenfield client is destroyed?
          wlClient._clientRegistryProxy = localClient.connection.createRegistry()
          resolve(localClient)
        } else {
          this.primaryConnection = wfcConnection

          const registryProxy = wfcConnection.createRegistry()
          registryProxy.listener.global = (name, interface_, version) => {
            if (interface_ === session.GrSession.name) {
              const grSessionProxy = registryProxy.bind(name, interface_, version)
              grSessionProxy.listener = this
              this.grSessionProxy = grSessionProxy

              resolve(this)
            } else if (interface_.startsWith('Gr')) {
              this._setupShimGlobal(name, interface_, version)
            }
          }

          registryProxy.listener.globalRemove = (name) => {
            this._tearDownShimGlobal(name)
          }
        }
      })
    })
  }

  /**
   *
   * @param {WebSocket.Server} wss
   * @param wlDisplay
   */
  constructor (wss, wlDisplay) {
    this._wss = wss
    this.wlDisplay = wlDisplay
    this.primaryConnection = null
    this.connectionPromises = []
    this.globals = {}
  }

  _setupShimGlobal (name, interface_, version) {
    this.globals[name] = ShimGlobal.create(this.wlDisplay, name, interface_, version)
  }

  _tearDownShimGlobal (name) {
    delete this.globals[name]
    // TODO remove native wayland global
  }

  /**
   *@param wlClient
   * @returns {Promise<wfc.Connection>}
   */
  createConnection (wlClient) {
    return new Promise((resolve) => {
      resolve._wlClient = wlClient
      this.connectionPromises.push(resolve)
      this.grSessionProxy.client()
    })
  }

  /**
   * @since 1
   *
   */
  flush () {
    console.log('flushing')
    this.wlDisplay.flushClients()
  }
}
<commit_msg>disable log statement<commit_after>'use strict'

const westfield = require('westfield-runtime-client')
const session = require('./protocol/session-client-protocol')
const WebSocket = require('ws')

const ShimGlobal = require('./ShimGlobal')
const LocalClient = require('./LocalClient')

module.exports = class LocalSession {
  /**
   * @param request http ws upgrade request
   * @param socket http socket
   * @param head http head
   * @param wlDisplay
   * @returns {Promise<LocalSession>}
   */
  static create (request, socket, head, wlDisplay) {
    const wss = new WebSocket.Server({
      noServer: true
      // path: '/greenfield'
    })
    return new LocalSession(wss, wlDisplay)._handleUpgrade(request, socket, head)
  }

  _handleUpgrade (request, socket, head) {
    return new Promise((resolve) => {
      this._wss.handleUpgrade(request, socket, head, (ws) => {
        const wfcConnection = new westfield.Connection()

        wfcConnection.onSend = (data) => {
          if (ws.readyState === WebSocket.OPEN) {
            try {
              ws.send(data, (error) => {
                if (error !== undefined) {
                  console.error(error)
                  ws.close()
                }
              })
            } catch (error) {
              console.error(error)
              ws.close()
            }
          }
        }

        ws.onmessage = (event) => {
          if (ws.readyState === WebSocket.OPEN) {
            try {
              const b = event.data
              const arrayBuffer = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength)
              wfcConnection.unmarshall(arrayBuffer)
            } catch (error) {
              console.error(error)
              ws.close()
            }
          }
        }

        ws.on('close', () => wfcConnection.close())
        wfcConnection.onClose().then(() => ws.close()).catch((error) => console.log(error))

        // TODO listen for error

        if (this.primaryConnection) {
          const resolve = this.connectionPromises.shift()
          const wlClient = resolve._wlClient
          delete resolve._wlClient
          const localClient = LocalClient.create(wfcConnection, wlClient)
          // TODO destroy proxy once wayland or greenfield client is destroyed?
          wlClient._clientRegistryProxy = localClient.connection.createRegistry()
          resolve(localClient)
        } else {
          this.primaryConnection = wfcConnection

          const registryProxy = wfcConnection.createRegistry()
          registryProxy.listener.global = (name, interface_, version) => {
            if (interface_ === session.GrSession.name) {
              const grSessionProxy = registryProxy.bind(name, interface_, version)
              grSessionProxy.listener = this
              this.grSessionProxy = grSessionProxy

              resolve(this)
            } else if (interface_.startsWith('Gr')) {
              this._setupShimGlobal(name, interface_, version)
            }
          }

          registryProxy.listener.globalRemove = (name) => {
            this._tearDownShimGlobal(name)
          }
        }
      })
    })
  }

  /**
   *
   * @param {WebSocket.Server} wss
   * @param wlDisplay
   */
  constructor (wss, wlDisplay) {
    this._wss = wss
    this.wlDisplay = wlDisplay
    this.primaryConnection = null
    this.connectionPromises = []
    this.globals = {}
  }

  _setupShimGlobal (name, interface_, version) {
    this.globals[name] = ShimGlobal.create(this.wlDisplay, name, interface_, version)
  }

  _tearDownShimGlobal (name) {
    delete this.globals[name]
    // TODO remove native wayland global
  }

  /**
   *@param wlClient
   * @returns {Promise<wfc.Connection>}
   */
  createConnection (wlClient) {
    return new Promise((resolve) => {
      resolve._wlClient = wlClient
      this.connectionPromises.push(resolve)
      this.grSessionProxy.client()
    })
  }

  /**
   * @since 1
   *
   */
  flush () {
    // console.log('flushing')
    this.wlDisplay.flushClients()
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at http://www.mozillapopcorn.org/butter-license.txt */

define( [], function(){

  var CHECK_MEDIA_INTERVAL = 50,
      SCROLL_INTERVAL = 16,
      SCROLL_DISTANCE = 20,
      MOUSE_SCRUBBER_PIXEL_WINDOW = 3;

  return function( parentElement, media, tracksContainer, hScrollbar ){
    var _container = document.createElement( "div" ),
        _node = document.createElement( "div" ),
        _line = document.createElement( "div" ),
        _fill = document.createElement( "div" ),
        _tracksContainer = tracksContainer,
        _tracksContainerWidth,
        _element = parentElement,
        _media = media,
        _mouseDownPos,
        _currentMousePos,
        _zoom = 1,
        _scrollInterval = -1,
        _rect,
        _mediaCheckInterval,
        _width,
        _isPlaying = false,
        _isScrubbing = false,
        _lastTime = -1,
        _lastScroll = _tracksContainer.element.scrollLeft,
        _lastZoom = -1,
        _this = this;

    _container.className = "time-bar-scrubber-container";
    _node.className = "time-bar-scrubber-node";
    _line.className = "time-bar-scrubber-line";
    _fill.className = "fill-bar";

    _node.appendChild( _line );
    _container.appendChild( _fill );
    _container.appendChild( _node );
    _element.appendChild( _container );

    function setNodePosition(){
      var duration = _media.duration,
          currentTime = _media.currentTime,
          scrollLeft = _tracksContainer.element.scrollLeft;

      // if we can avoid re-setting position and visibility, then do so
      if( _lastTime !== currentTime || _lastScroll !== scrollLeft || _lastZoom !== _zoom ){
        var pos = currentTime / duration * _tracksContainerWidth,
            adjustedPos = pos - scrollLeft;

        if( pos <  scrollLeft || pos > _width + scrollLeft ){
          _node.style.display = "none";
        }
        else {
          _node.style.left = adjustedPos + "px";
          _node.style.display = "block";
        } //if

        if( pos < scrollLeft ){
          _fill.style.display = "none";
        }
        else {
          if( pos > _width + scrollLeft ){
            _fill.style.width = ( _width - 2 ) + "px";
          }
          else {
            _fill.style.width = adjustedPos + "px";
          } //if
          _fill.style.display = "block";
        } //if

      } //if

      _lastTime = currentTime;
      _lastScroll = scrollLeft;

    } //setNodePosition

    hScrollbar.listen( "scroll", setNodePosition );

    function onMouseUp( e ){
      if( _isPlaying ){
        _media.play();
        _isScrubbing = false;
      }

      clearInterval( _scrollInterval );
      _scrollInterval = -1;

      window.removeEventListener( "mouseup", onMouseUp, false );
      window.removeEventListener( "mousemove", onMouseMove, false );
    } //onMouseUp

    function scrollTracksContainer( direction ){
      if( direction === "right" ){
        _scrollInterval = setInterval(function(){
          if( _currentMousePos < _rect.right - MOUSE_SCRUBBER_PIXEL_WINDOW ){
            clearInterval( _scrollInterval );
            _scrollInterval = -1;
          }
          else{
            _currentMousePos += SCROLL_DISTANCE;
            _tracksContainer.scrollLeft += SCROLL_DISTANCE;
            evalMousePosition();
            setNodePosition();
          }
        }, SCROLL_INTERVAL );
      }
      else{
        _scrollInterval = setInterval(function(){
          if( _currentMousePos > _rect.left + MOUSE_SCRUBBER_PIXEL_WINDOW ){
            clearInterval( _scrollInterval );
            _scrollInterval = -1;
          }
          else{
            _currentMousePos -= SCROLL_DISTANCE;
            _tracksContainer.scrollLeft -= SCROLL_DISTANCE;
            evalMousePosition();
            setNodePosition();
          }
        }, SCROLL_INTERVAL );
      }
    } //scrollTracksContainer

    function evalMousePosition(){
      var diff = _currentMousePos - _mouseDownPos;
      diff = Math.max( 0, Math.min( diff, _width ) );
      _media.currentTime = ( diff + _tracksContainer.element.scrollLeft ) / _tracksContainerWidth * _media.duration;
    } //evalMousePosition

    function onMouseMove( e ){
      _currentMousePos = e.pageX;

      if( _scrollInterval === -1 ){
        if( _currentMousePos > _rect.right - MOUSE_SCRUBBER_PIXEL_WINDOW ){
          scrollTracksContainer( "right" );
        }
        else if( _currentMousePos < _rect.left + MOUSE_SCRUBBER_PIXEL_WINDOW ){
          scrollTracksContainer( "left" );
        } //if
      } //if

      evalMousePosition();
      setNodePosition();
    } //onMouseMove

    function onScrubberMouseDown( e ){
      _mouseDownPos = e.pageX - _node.offsetLeft;

      if( _isPlaying ){
        _media.pause();
        _isScrubbing = true;
      }

      _node.removeEventListener( "mousedown", onScrubberMouseDown, false );
      window.addEventListener( "mousemove", onMouseMove, false );
      window.addEventListener( "mouseup", onMouseUp, false );
    } //onMouesDown

    var onMouseDown = this.onMouseDown = function( e ){
      var pos = e.pageX - _container.getBoundingClientRect().left;
      _media.currentTime = ( pos + _tracksContainer.element.scrollLeft ) / _tracksContainerWidth * _media.duration;
      setNodePosition();
      onScrubberMouseDown( e );
    }; //onMouseDown

    _node.addEventListener( "mousedown", onScrubberMouseDown, false );
    _container.addEventListener( "mousedown", onMouseDown, false );

    this.update = function( zoom ){
      _zoom = zoom || _zoom;
      _tracksContainerWidth = _tracksContainer.container.getBoundingClientRect().width;
      _width = _element.getBoundingClientRect().width;
      _width = Math.min( _width, _tracksContainerWidth );
      _container.style.width = _width + "px";
      _rect = _container.getBoundingClientRect();
      setNodePosition();
    }; //update

    window.addEventListener( "resize", _this.update, false );

    function checkMedia(){
      setNodePosition();
    } //checkMedia

    _media.listen( "mediaplaying", function( e ){
      _isPlaying = true;
    });

    _media.listen( "mediapause", function( e ){
      if( !_isScrubbing ){
        _isPlaying = false;
      }
    });

    _checkMediaInterval = setInterval( checkMedia, CHECK_MEDIA_INTERVAL );

    this.destroy = function(){
      clearInterval( _checkMediaInterval );
    }; //destroy
  };
});
<commit_msg>[t94] - Rebase and fix for timeline scrolling<commit_after>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at http://www.mozillapopcorn.org/butter-license.txt */

define( [], function(){

  var CHECK_MEDIA_INTERVAL = 50,
      SCROLL_INTERVAL = 16,
      SCROLL_DISTANCE = 20,
      MOUSE_SCRUBBER_PIXEL_WINDOW = 3;

  return function( parentElement, media, tracksContainer, hScrollbar ){
    var _container = document.createElement( "div" ),
        _node = document.createElement( "div" ),
        _line = document.createElement( "div" ),
        _fill = document.createElement( "div" ),
        _tracksContainer = tracksContainer,
        _tracksContainerWidth,
        _element = parentElement,
        _media = media,
        _mouseDownPos,
        _currentMousePos,
        _zoom = 1,
        _scrollInterval = -1,
        _rect,
        _mediaCheckInterval,
        _width,
        _isPlaying = false,
        _isScrubbing = false,
        _lastTime = -1,
        _lastScroll = _tracksContainer.element.scrollLeft,
        _lastZoom = -1,
        _this = this;

    _container.className = "time-bar-scrubber-container";
    _node.className = "time-bar-scrubber-node";
    _line.className = "time-bar-scrubber-line";
    _fill.className = "fill-bar";

    _node.appendChild( _line );
    _container.appendChild( _fill );
    _container.appendChild( _node );
    _element.appendChild( _container );

    function setNodePosition(){
      var duration = _media.duration,
          currentTime = _media.currentTime,
          scrollLeft = _tracksContainer.element.scrollLeft;

      // if we can avoid re-setting position and visibility, then do so
      if( _lastTime !== currentTime || _lastScroll !== scrollLeft || _lastZoom !== _zoom ){
        var pos = currentTime / duration * _tracksContainerWidth,
            adjustedPos = pos - scrollLeft;

        if( pos <  scrollLeft || pos > _width + scrollLeft ){
          _node.style.display = "none";
        }
        else {
          _node.style.left = adjustedPos + "px";
          _node.style.display = "block";
        } //if

        if( pos < scrollLeft ){
          _fill.style.display = "none";
        }
        else {
          if( pos > _width + scrollLeft ){
            _fill.style.width = ( _width - 2 ) + "px";
          }
          else {
            _fill.style.width = adjustedPos + "px";
          } //if
          _fill.style.display = "block";
        } //if

      } //if

      _lastTime = currentTime;
      _lastScroll = scrollLeft;

    } //setNodePosition

    hScrollbar.listen( "scroll", setNodePosition );

    function onMouseUp( e ){
      if( _isPlaying ){
        _media.play();
        _isScrubbing = false;
      }

      clearInterval( _scrollInterval );
      _scrollInterval = -1;

      window.removeEventListener( "mouseup", onMouseUp, false );
      window.removeEventListener( "mousemove", onMouseMove, false );
    } //onMouseUp

    function scrollTracksContainer( direction ){
      if( direction === "right" ){
        _scrollInterval = setInterval(function(){
          if( _currentMousePos < _rect.right - MOUSE_SCRUBBER_PIXEL_WINDOW ){
            clearInterval( _scrollInterval );
            _scrollInterval = -1;
          }
          else{
            _currentMousePos += SCROLL_DISTANCE;
            _tracksContainer.element.scrollLeft += SCROLL_DISTANCE;
            evalMousePosition();
            setNodePosition();
          }
        }, SCROLL_INTERVAL );
      }
      else{
        _scrollInterval = setInterval(function(){
          if( _currentMousePos > _rect.left + MOUSE_SCRUBBER_PIXEL_WINDOW ){
            clearInterval( _scrollInterval );
            _scrollInterval = -1;
          }
          else{
            _currentMousePos -= SCROLL_DISTANCE;
            _tracksContainer.element.scrollLeft -= SCROLL_DISTANCE;
            evalMousePosition();
            setNodePosition();
          }
        }, SCROLL_INTERVAL );
      }
    } //scrollTracksContainer

    function evalMousePosition(){
      var diff = _currentMousePos - _mouseDownPos;
      diff = Math.max( 0, Math.min( diff, _width ) );
      _media.currentTime = ( diff + _tracksContainer.element.scrollLeft ) / _tracksContainerWidth * _media.duration;
    } //evalMousePosition

    function onMouseMove( e ){
      _currentMousePos = e.pageX;

      if( _scrollInterval === -1 ){
        if( _currentMousePos > _rect.right - MOUSE_SCRUBBER_PIXEL_WINDOW ){
          scrollTracksContainer( "right" );
        }
        else if( _currentMousePos < _rect.left + MOUSE_SCRUBBER_PIXEL_WINDOW ){
          scrollTracksContainer( "left" );
        } //if
      } //if

      evalMousePosition();
      setNodePosition();
    } //onMouseMove

    function onScrubberMouseDown( e ){
      _mouseDownPos = e.pageX - _node.offsetLeft;

      if( _isPlaying ){
        _media.pause();
        _isScrubbing = true;
      }

      _node.removeEventListener( "mousedown", onScrubberMouseDown, false );
      window.addEventListener( "mousemove", onMouseMove, false );
      window.addEventListener( "mouseup", onMouseUp, false );
    } //onMouesDown

    var onMouseDown = this.onMouseDown = function( e ){
      var pos = e.pageX - _container.getBoundingClientRect().left;
      _media.currentTime = ( pos + _tracksContainer.element.scrollLeft ) / _tracksContainerWidth * _media.duration;
      setNodePosition();
      onScrubberMouseDown( e );
    }; //onMouseDown

    _node.addEventListener( "mousedown", onScrubberMouseDown, false );
    _container.addEventListener( "mousedown", onMouseDown, false );

    this.update = function( zoom ){
      _zoom = zoom || _zoom;
      _tracksContainerWidth = _tracksContainer.container.getBoundingClientRect().width;
      _width = _element.getBoundingClientRect().width;
      _width = Math.min( _width, _tracksContainerWidth );
      _container.style.width = _width + "px";
      _rect = _container.getBoundingClientRect();
      setNodePosition();
    }; //update

    window.addEventListener( "resize", _this.update, false );

    function checkMedia(){
      setNodePosition();
    } //checkMedia

    _media.listen( "mediaplaying", function( e ){
      _isPlaying = true;
    });

    _media.listen( "mediapause", function( e ){
      if( !_isScrubbing ){
        _isPlaying = false;
      }
    });

    _checkMediaInterval = setInterval( checkMedia, CHECK_MEDIA_INTERVAL );

    this.destroy = function(){
      clearInterval( _checkMediaInterval );
    }; //destroy
  };
});
<|endoftext|>


<commit_before>/* Makes Debiki work in a child iframe.
 * Copyright (C) 2013-2014 Kaj Magnus Lindberg (born 1979)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Some files assume this has been defined:
window.debiki. internal = {};
window.debiki.v0 = { util: {} };

addEventListener('message', onMessage, false);

// Find Debiki server origin, by extracting origin of the debiki-embedded-comments.js script.
// Then the website admin won't need to repeat the site id or address anywhere.
var debikiServerOrigin = (function() {
  var origin;
  $('script').each(function() {
    script = $(this);
    var srcAttr = script.attr('src');
    var isEmbeddedCommentsScript = srcAttr.search(/\/-\/debiki-embedded-comments.js/) !== -1;
    if (isEmbeddedCommentsScript) {
      origin = srcAttr.match(/^[^/]*\/\/[^/]+/)[0];
    }
  });
  if (!origin && console.error) {
    console.error(
      'Error extracting Debiki server origin, is there no "/-/debiki-embedded-comments.js" script?');
  }
  return origin;
})();

// Add `src` and `seamless` attributs to Debiki embedded comments s.
$('.debiki-embedded-comments')
  .width($(window).width())
  .css('border', 'none')
  .attr('seamless', 'seamless')
  .each(function() {
    var iframe = $(this);
    var pageId = iframe.attr('data-topic-id');
    var iframePath = '/-/embed/comments/' + pageId;
    var iframeUrl = debikiServerOrigin + iframePath;
    iframe.attr('src', iframeUrl);
  });

// Enable Utterscroll in parent window.
// Once the iframe has been loaded, Utterscroll will run in the iframe too,
// and the two Utterscroll instances will cooperate via `window.postMessage`.
jQuery(function($) {
  if (!Modernizr.touch) { // if not a smartphone
    debiki.Utterscroll.enable();
  }
});

function onMessage(event) {
  var eventName = event.data[0];
  var eventData = event.data[1];
  switch (eventName) {
    case 'iframeInited':
      setIframeBaseAddress(findIframeThatSent(event));
      break;
    case 'setIframeSize':
      setIframeSize(findIframeThatSent(event), eventData);
      break;
    case 'startUtterscrolling':
      debiki.Utterscroll.startScrolling(eventData);
      break;
    case 'onMouseMove':
    case 'doUtterscroll':
      debiki.Utterscroll.doScroll(eventData);
      break;
    case 'stopUtterscrolling':
      debiki.Utterscroll.stopScrolling(eventData);
      break;
  }
};

function setIframeBaseAddress(iframe) {
  iframe.contentWindow.postMessage(['setBaseAddress', window.location.href], '*');
};

function setIframeSize(iframe, dimensions) {
  $(iframe).width(dimensions.width);
  $(iframe).height(dimensions.height);
};

function findIframeThatSent(event) {
  // See http://stackoverflow.com/a/18267415/694469
  var iframes = document.getElementsByClassName('debiki-embedded-comments');
  for (var i = 0; i < iframes.length; ++i) {
    var iframe = iframes[i];
    if (iframe.contentWindow === event.source)
      return iframe;
  }
};

// vim: fdm=marker et ts=2 sw=2 fo=tcqwn list
<commit_msg>Show "Loading comments..." message until iframe loaded.<commit_after>/* Makes Debiki work in a child iframe.
 * Copyright (C) 2013-2014 Kaj Magnus Lindberg (born 1979)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Some files assume this has been defined:
window.debiki. internal = {};
window.debiki.v0 = { util: {} };

addEventListener('message', onMessage, false);

// Find Debiki server origin, by extracting origin of the debiki-embedded-comments.js script.
// Then the website admin won't need to repeat the site id or address anywhere.
var debikiServerOrigin = (function() {
  var origin;
  $('script').each(function() {
    script = $(this);
    var srcAttr = script.attr('src');
    var isEmbeddedCommentsScript = srcAttr.search(/\/-\/debiki-embedded-comments.js/) !== -1;
    if (isEmbeddedCommentsScript) {
      origin = srcAttr.match(/^[^/]*\/\/[^/]+/)[0];
    }
  });
  if (!origin && console.error) {
    console.error(
      'Error extracting Debiki server origin, is there no "/-/debiki-embedded-comments.js" script?');
  }
  return origin;
})();

// Hide Debiki embedded comments iframes until they've been loaded,
// show "Loading comments..." message instead.
// Also add `src` and `seamless` attributs to Debiki embedded comments s.
$('.debiki-embedded-comments')
  .hide()
  .before($('
Loading comments...
'))
  .width($(window).width())
  .css('border', 'none')
  .attr('seamless', 'seamless')
  .each(function() {
    var iframe = $(this);
    var pageId = iframe.attr('data-topic-id');
    var iframePath = '/-/embed/comments/' + pageId;
    var iframeUrl = debikiServerOrigin + iframePath;
    iframe.attr('src', iframeUrl);
  });

// Enable Utterscroll in parent window.
// Once the iframe has been loaded, Utterscroll will run in the iframe too,
// and the two Utterscroll instances will cooperate via `window.postMessage`.
jQuery(function($) {
  if (!Modernizr.touch) { // if not a smartphone
    debiki.Utterscroll.enable();
  }
});

function onMessage(event) {
  var eventName = event.data[0];
  var eventData = event.data[1];
  switch (eventName) {
    case 'iframeInited':
      setIframeBaseAddress(findIframeThatSent(event));
      break;
    case 'setIframeSize':
      var iframe = $(findIframeThatSent(event));
      iframe.show();
      setIframeSize(iframe, eventData);
      // Remove "loadin comments" message.
      // This currently removes that message for all <iframes> if there're more
      // than one. Doesn't matter much.
      iframe.parent().children('.debiki-loading-comments-message').remove();
      break;
    case 'startUtterscrolling':
      debiki.Utterscroll.startScrolling(eventData);
      break;
    case 'onMouseMove':
    case 'doUtterscroll':
      debiki.Utterscroll.doScroll(eventData);
      break;
    case 'stopUtterscrolling':
      debiki.Utterscroll.stopScrolling(eventData);
      break;
  }
};

function setIframeBaseAddress(iframe) {
  iframe.contentWindow.postMessage(['setBaseAddress', window.location.href], '*');
};

function setIframeSize(iframe, dimensions) {
  $(iframe).width(dimensions.width);
  $(iframe).height(dimensions.height);
};

function findIframeThatSent(event) {
  // See http://stackoverflow.com/a/18267415/694469
  var iframes = document.getElementsByClassName('debiki-embedded-comments');
  for (var i = 0; i < iframes.length; ++i) {
    var iframe = iframes[i];
    if (iframe.contentWindow === event.source)
      return iframe;
  }
};

// vim: fdm=marker et ts=2 sw=2 fo=tcqwn list
<|endoftext|>


<commit_before>exports.config = {
  //directConnect: true,

  seleniumAddress: 'http://localhost:4444/wd/hub',

  capabilities: {
    browserName: 'chrome',
    chromeOptions: {
      args: [
        $CHROME_OPTIONS
      ]
    }
  }
};
<commit_msg>Remove commented code<commit_after>exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',

  capabilities: {
    browserName: 'chrome',
    chromeOptions: {
      args: [
        $CHROME_OPTIONS
      ]
    }
  }
};
<|endoftext|>


<commit_before>"use strict";

var canvas;
var gl;
var program;

var pos_matrix;
var u_pos_matrix;

var perspective;
var u_perspective;

var rot_matrix;

var shape;
var theta = 0.0;

var vertex_buffer;
var v_position;

var color_buffer;
var v_color;

var to_radians = Math.PI / 180.0;

var primitive = 2;

window.onload = function init()
{
    canvas = document.getElementById("webgl-canvas");
    gl = WebGLUtils.setupWebGL(canvas);
    if(gl)
    {
	setup();
	render();
    }
    else
    { alert("Failed initialising WebGL"); }
}

function setup()
{
    gl.viewport(0 , 0 , gl.drawingBufferWidth , gl.drawingBufferHeight);
    gl.clearColor(0.0 , 0.0 , 0.0 , 1.0);

    program = init_program(gl , "vertex-shader" , "fragment-shader");
    gl.useProgram(program);

    shape = create_tetra();

    pos_matrix = mat4.create();
    pos_matrix = mat4.identity(pos_matrix);
    pos_matrix = mat4.translate(pos_matrix , pos_matrix , [0.0 , 0.0 , -4.0]);

    perspective = mat4.create();
    perspective = mat4.identity(perspective);
    perspective = mat4.perspective
    (
	perspective ,
	45.0 ,
	gl.viewportWidth / gl.viewportHeight ,
	0.1 ,
	100.0
    );
    perspective[0] = 1.7;

    rot_matrix = mat4.create();
}

function render()
{
    vertex_buffer = bind_buffer(gl , shape , vertex_buffer);
    v_position = bind_attribute(gl , program , "v_position" , 3 , v_position);

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	pos_matrix ,
	theta++ * to_radians ,
	[0 , 1 , 1]
    );

    u_pos_matrix = gl.getUniformLocation(program , "u_pos_matrix");
    gl.uniformMatrix4fv(u_pos_matrix , false , rot_matrix);

    u_perspective = gl.getUniformLocation(program , "u_perspective");
    gl.uniformMatrix4fv(u_perspective , false , perspective);

    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(primitive , 0 , shape.length / 3);

    requestAnimFrame(render);
}

function update_primitive(type)
{
    if(0 <= primitive && primitive <= 6)
	primitive = type;
}

function create_tetra()
{
    var nodes = [];
    var pos = Math.PI / 2;
    var faces = 3;
    var angle = (2 * Math.PI) / faces;
    for(var i = 0; i < faces * 3; i += 3)
    {
	nodes[i] = Math.cos(pos);
	nodes[i + 1] = Math.sin(pos);
	nodes[i + 2] = 0.0;
	pos += angle;
    }
    return nodes;
}
<commit_msg>Beginnings of a spere routine.<commit_after>"use strict";

var canvas;
var gl;
var program;

var pos_matrix;
var u_pos_matrix;

var perspective;
var u_perspective;

var rot_matrix;

var shape;
var theta = 0.0;

var vertex_buffer;
var v_position;

var color_buffer;
var v_color;

var to_radians = Math.PI / 180.0;

var primitive = 2;

window.onload = function init()
{
    canvas = document.getElementById("webgl-canvas");
    gl = WebGLUtils.setupWebGL(canvas);
    if(gl)
    {
	setup();
	render();
    }
    else
    { alert("Failed initialising WebGL"); }
}

function setup()
{
    gl.viewport(0 , 0 , gl.drawingBufferWidth , gl.drawingBufferHeight);
    gl.clearColor(1.0 , 1.0 , 1.0 , 1.0);
    gl.lineWidth(10.0);

    program = init_program(gl , "vertex-shader" , "fragment-shader");
    gl.useProgram(program);

    shape = create_sphere();

    pos_matrix = mat4.create();
    pos_matrix = mat4.identity(pos_matrix);
    pos_matrix = mat4.translate(pos_matrix , pos_matrix , [0.0 , 0.0 , -4.0]);

    perspective = mat4.create();
    perspective = mat4.identity(perspective);
    perspective = mat4.perspective
    (
	perspective ,
	45.0 ,
	gl.viewportWidth / gl.viewportHeight ,
	0.1 ,
	100.0
    );
    perspective[0] = 1.7;

    rot_matrix = mat4.create();
}

function render()
{
    vertex_buffer = bind_buffer(gl , shape , vertex_buffer);
    v_position = bind_attribute(gl , program , "v_position" , 3 , v_position);

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	pos_matrix ,
	theta++ * to_radians ,
	[0 , 1 , 1]
    );

    u_pos_matrix = gl.getUniformLocation(program , "u_pos_matrix");
    gl.uniformMatrix4fv(u_pos_matrix , false , rot_matrix);

    u_perspective = gl.getUniformLocation(program , "u_perspective");
    gl.uniformMatrix4fv(u_perspective , false , perspective);

    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(primitive , 0 , shape.length / 3);

    requestAnimFrame(render);
}

function update_primitive(type)
{
    if(0 <= primitive && primitive <= 6)
	primitive = type;
}

// learningwebgl / webkit team method.
function create_sphere()
{
    var nodes = [];
    var horizontals = 100;
    var horizontal_slice = Math.PI / horizontals;
    var verticals = 10;
    var vertical_slice = 2 * Math.PI / verticals;
    for(var lattitude = 0; lattitude < horizontals ; lattitude++)
    {
	var theta = lattitude * horizontal_slice;
	var sin_theta = Math.sin(theta);
	var cos_theta = Math.cos(theta);

	for(var longitude = 0; longitude < verticals ; longitude++)
	{
	    var phi = longitude * vertical_slice;
	    var sin_phi = Math.sin(phi);
	    var cos_phi = Math.cos(phi);

	    var x = cos_phi * sin_theta;
	    var y = cos_theta;
	    var z = sin_phi * sin_theta;
	    nodes.push(x);
	    nodes.push(y);
	    nodes.push(z);
	}
    }
    return nodes;
}
<|endoftext|>