<commit_before>var assert = require('assert');
var dgram = require('dgram');
var response = require('./response.js');
var request = require('./request.js');

/**
 * Create a new server using a certain socket
 *
 * @constructor
 * @this Server
 * @param {Socket} socket
 * @api private
 */
function Server(socket, response, request) {
  this.socket = socket;
  this.Response = response;
  this.Request = request;
  this.handlers = {}
}

/**
 * Set a callback function for a command
 *
 * @param {string} command
 * @param {function} fn Callback that will be executed when datagram with this
 * command is received
 * @api public
 */
Server.prototype.receive = function(command, fn) {
  assert.deepEqual(typeof command, 'string', 'First argument must be a string');
  assert.deepEqual(typeof fn, 'function', 'Second argument must be a function');

  if (typeof this.handlers[command] !== 'undefined') {
    throw new Error('Handler already set for this command');
  }

  this.handlers[command] = fn;

}

/**
 * Binds a server to a port and address
 *
 * @param {number} port
 * @param {string} address Host or IP address
 * @api public
 */
Server.prototype.bind = function(port, address) {
  assert.deepEqual(typeof port, 'number', 'First argument must be an integer');

  this.port = port;
  this.address = address || 'localhost';

  this.socket.bind(port, address);
  this._bootstrap();
}

/**
 * Set a callback which will be executed when the socket is successfully
 * bound to the port
 *
 * @param {function} fn Callback function
 * @api public
 */
Server.prototype.init = function(fn) {
  assert.deepEqual(typeof fn, 'function', 'First argument must be a function');
  this.receive('init', fn);
}

/**
 * Hooks up different events
 *
 * @api private
 */
Server.prototype._bootstrap = function() {

  // Bind this to the functions so this is not replaced by the EventEmitter
  // object in the callback functions
  this.socket.on('listening', this._processInit.bind(this));
  this.socket.on('message', this._processMessage.bind(this));
}

/**
 * Executed the init function if set
 *
 * @api private
 */
Server.prototype._processInit = function() {

  if (typeof this.handlers.init === 'undefined') return false;
  var res = new this.Response(this.socket, {

      // These properties should be dynamic
      address: '127.0.0.1',
      port: 8000,
    }
  );

  this.handlers.init(res);
}

/**
 * Handles incoming datagrams
 *
 * @param {Buffer} buffer Message buffer
 * @param {object} requestInfo Information about the incoming request
 * @api private
 */
Server.prototype._processMessage = function(buffer, requestInfo) {

  // Unpack the MsgPack buffer so we can determine the command
  req = new this.Request(buffer, requestInfo);

  // Check if there is a handler for this command
  if (typeof this.handlers[req.command] === 'undefined') {
    throw new Error('No handler for command ' + req.command);
  }

  res = new this.Response(this.socket, requestInfo);
  this.handlers[req.command](req, res);
}

/**
 * Factory method for creating a new server
 *
 * @return {Server}
 * @api public
 */
module.exports.createServer = function() {
  var socket = dgram.createSocket('udp4');
  return new Server(socket);
}

// We also want to export Server when we're running in a test env so we
// can check the returned object from the createServer function
if (process.env.NODE_ENV === 'test') module.exports.Server = Server;<commit_msg>Renamed _bootstrap method to _addEventListeners.<commit_after>var assert = require('assert');
var dgram = require('dgram');
var response = require('./response.js');
var request = require('./request.js');

/**
 * Create a new server using a certain socket
 *
 * @constructor
 * @this Server
 * @param {Socket} socket
 * @api private
 */
function Server(socket, response, request) {
  this.socket = socket;
  this.Response = response;
  this.Request = request;
  this.handlers = {}
}

/**
 * Set a callback function for a command
 *
 * @param {string} command
 * @param {function} fn Callback that will be executed when datagram with this
 * command is received
 * @api public
 */
Server.prototype.receive = function(command, fn) {
  assert.deepEqual(typeof command, 'string', 'First argument must be a string');
  assert.deepEqual(typeof fn, 'function', 'Second argument must be a function');

  if (typeof this.handlers[command] !== 'undefined') {
    throw new Error('Handler already set for this command');
  }

  this.handlers[command] = fn;

}

/**
 * Binds a server to a port and address
 *
 * @param {number} port
 * @param {string} address Host or IP address
 * @api public
 */
Server.prototype.bind = function(port, address) {
  assert.deepEqual(typeof port, 'number', 'First argument must be an integer');

  this.port = port;
  this.address = address || 'localhost';

  this.socket.bind(port, address);
  this._addEventListeners();
}

/**
 * Set a callback which will be executed when the socket is successfully
 * bound to the port
 *
 * @param {function} fn Callback function
 * @api public
 */
Server.prototype.init = function(fn) {
  assert.deepEqual(typeof fn, 'function', 'First argument must be a function');
  this.receive('init', fn);
}

/**
 * Hooks up different events
 *
 * @api private
 */
Server.prototype._addEventListeners = function() {

  // Bind this to the functions so this is not replaced by the EventEmitter
  // object in the callback functions
  this.socket.on('listening', this._processInit.bind(this));
  this.socket.on('message', this._processMessage.bind(this));
}

/**
 * Executed the init function if set
 *
 * @api private
 */
Server.prototype._processInit = function() {

  if (typeof this.handlers.init === 'undefined') return false;
  var res = new this.Response(this.socket, {

      // These properties should be dynamic
      address: '127.0.0.1',
      port: 8000,
    }
  );

  this.handlers.init(res);
}

/**
 * Handles incoming datagrams
 *
 * @param {Buffer} buffer Message buffer
 * @param {object} requestInfo Information about the incoming request
 * @api private
 */
Server.prototype._processMessage = function(buffer, requestInfo) {

  // Unpack the MsgPack buffer so we can determine the command
  req = new this.Request(buffer, requestInfo);

  // Check if there is a handler for this command
  if (typeof this.handlers[req.command] === 'undefined') {
    throw new Error('No handler for command ' + req.command);
  }

  res = new this.Response(this.socket, requestInfo);
  this.handlers[req.command](req, res);
}

/**
 * Factory method for creating a new server
 *
 * @return {Server}
 * @api public
 */
module.exports.createServer = function() {
  var socket = dgram.createSocket('udp4');
  return new Server(socket);
}

// We also want to export Server when we're running in a test env so we
// can check the returned object from the createServer function
if (process.env.NODE_ENV === 'test') module.exports.Server = Server;<|endoftext|>


<commit_before>/* Cascading-reactor defs & helpers */

// Symbols for private properties
const _value = Symbol('_value');
const _parent = Symbol('_parent');
const _children = Symbol('_children');
const _then = Symbol('_then');
const _finally = Symbol('_finally');

// Symbols for private methods
const _cancel = Symbol('_cancel');
const _addchild = Symbol('_addchild');
const _delchild = Symbol('_delchild');

export class Reactor {
	constructor(newval, thenfunc, finalfunc) {
		// Params thenfunc and finalfunc are optional
		// Must be functions if given, however

		if ((thenfunc === undefined) || (thenfunc === null)) {
			this[_then] = null;
		}
		else if (typeof thenfunc === 'function') {
			this[_then] = thenfunc;
		}
		else {
			throw new Error("Param 'thenfunc' must be a function");
		}

		if ((finalfunc === undefined) || (finalfunc === null)) {
			this[_finally] = null;
		}
		else if (typeof finalfunc === 'function') {
			this[_finally] = finalfunc;
		}
		else {
			throw new Error("Param 'finalfunc' must be a function");
		}

		// Initial value
		var initval;

		// If newval is another Reactor, set it as parent
		if (newval instanceof Reactor) {
			// Add this to parent's child set
			this[_parent] = newval[_addchild](this);
			// Get initial value from parent
			initval = newval.value;
		}
		else {
			// If newval is standalone, no parent
			this[_parent] = null;
			// Use provided initial value
			initval = newval;
		}

		// Start with empty child list
		this[_children] = new Set();

		// Function thenfunc run once if present
		// and given/parent value isn't undefined
		if ((initval !== undefined) && (this[_then] !== null)) {
			this[_value] = this[_then](initval);
		}
		else {
			// Nothing to run or nothing to be run on
			// Value will be undefined if initval is
			this[_value] = initval;
		}

	}

	get value() {
		return this[_value];
	}

	set value(val) {
		var oldval = this[_value];
		var newval = (this[_then] !== null) ? this[_then](val, oldval) : val;

		// Only triggers cascade if value actually changed
		if ((newval !== oldval) && (newval !== undefined)) {
			this[_value] = newval;
			this[_children].forEach(child => {child.value = newval});
		}
		else {
			// Set and pass along the raw value instead if newval is undefined
			this[_value] = val;
			this[_children].forEach(child => {child.value = val});
		}
	}

	get parent() {
		return this[_parent];
	}

	// Leaving setter in for now
	// Might be easier for collection reactors later on if whole collection is changed and compared
	set parent(par) {
		if (this[_parent] !== par) {
			if (this[_parent] !== null) {
				// Remove from parent's child set
				this.detach();
			}
			if (par instanceof Reactor) {
				// Set new parent, add this to new parent's child set, and recalculate value
				this[_parent] = par[_addchild](this);
				// Will invoke setter and thus cascade if appropriate
				this.value = par.value;
			}
		}
	}

	// Returns new reactor with given thenfunc and/or finalfunc
	then (thenfunc, finalfunc) {
		return new Reactor(this, thenfunc, finalfunc);
	}

	// Returns new reactor with no thenfunc and given finalfunc
	finally (finalfunc) {
		return new Reactor(this, null, finalfunc);
	}

	// Cancels reactor and cascades
	// All relations, callbacks, and values cleared
	cancel (final) {
		return this[_cancel](final, false);
	}

	// Removes from parent's child set and nulls parent
	detach (skipdelete) {
		if ((!skipdelete) && (this[_parent] !== null)) {
			this[_parent][_delchild](this);
		}
		// Clear parent regardless
		this[_parent] = null;
	}

	/*
		Private(ish) methods
	*/

	// Adds child to set
	[_addchild] (child) {
		this[_children].add(child);
		return this;
	}

	// Removes child from set
	[_delchild] (child) {
		// Error if child not in set
		// TODO: make this silent failure instead?
		if (!(this[_children].delete(child))) {
			throw new Error("Child not in set when _delchild() called: " + child.toString);
		}
		return this;
	}

	// Internal portion of cancel()
	[_cancel] (final, skipdelete) {
		// If finalfunc is set, will be called with (final, value) before
		// passing result downward
		var finalval = (this[_finally] !== null) ? this[_finally](final, this[_value]) : final;
		finalval = (finalval !== undefined) ? finalval : final;

		// Cascade to children (set skipdelete to true regardless of passed arg)
		this[_children].forEach(child => child[_cancel](finalval, true));

		// Clear children
		this[_children].clear();

		// Clear parent
		// If skipdelete is true, won't call delchild() on parent
		// (so parent can clean its own child set after cascading)
		this.detach(skipdelete);

		// Clear value, thenfunc, finalfunc
		this[_value] = null;
		this[_then] = null;
		this[_finally] = null;

		// Done
		return finalval;
	}
}

export function cr (initval) {
	return new Reactor(initval);
}

<commit_msg>Changed .value prop to get()/set(), changed .parent setter to attach()<commit_after>/* Cascading-reactor defs & helpers */

// Symbols for private properties
const _value = Symbol('_value');
const _parent = Symbol('_parent');
const _children = Symbol('_children');
const _then = Symbol('_then');
const _finally = Symbol('_finally');

// Symbols for private methods
const _cancel = Symbol('_cancel');
const _addchild = Symbol('_addchild');
const _delchild = Symbol('_delchild');

export class Reactor {
	constructor(newval, thenfunc, finalfunc) {
		// Params thenfunc and finalfunc are optional
		// Must be functions if given, however

		if ((thenfunc === undefined) || (thenfunc === null)) {
			this[_then] = null;
		}
		else if (typeof thenfunc === 'function') {
			this[_then] = thenfunc;
		}
		else {
			throw new Error("Param 'thenfunc' must be a function");
		}

		if ((finalfunc === undefined) || (finalfunc === null)) {
			this[_finally] = null;
		}
		else if (typeof finalfunc === 'function') {
			this[_finally] = finalfunc;
		}
		else {
			throw new Error("Param 'finalfunc' must be a function");
		}

		// Initial value
		var initval;

		// If newval is another Reactor, set it as parent
		if (newval instanceof Reactor) {
			// Add this to parent's child set
			this[_parent] = newval[_addchild](this);
			// Get initial value from parent
			initval = newval.get();
		}
		else {
			// If newval is standalone, no parent
			this[_parent] = null;
			// Use provided initial value
			initval = newval;
		}

		// Start with empty child list
		this[_children] = new Set();

		// Function thenfunc run once if present
		// and given/parent value isn't undefined
		if ((initval !== undefined) && (this[_then] !== null)) {
			this[_value] = this[_then](initval);
		}
		else {
			// Nothing to run or nothing to be run on
			// Value will be undefined if initval is
			this[_value] = initval;
		}

	}

	get () {
		return this[_value];
	}

	set (val) {
		var oldval = this[_value];
		var newval = (this[_then] !== null) ? this[_then](val, oldval) : val;

		// Only triggers cascade if value actually changed
		if ((newval !== oldval) && (newval !== undefined)) {
			this[_value] = newval;
			this[_children].forEach(child => child.set(newval));
		}
		// Set and pass along the raw value instead if newval is undefined
		else {
			this[_value] = val;
			this[_children].forEach(child => child.set(val));
		}
		return this[_value];
	}

	// Returns new reactor with given thenfunc and/or finalfunc
	then (thenfunc, finalfunc) {
		return new Reactor(this, thenfunc, finalfunc);
	}

	// Returns new reactor with no thenfunc and given finalfunc
	finally (finalfunc) {
		return new Reactor(this, null, finalfunc);
	}

	// Cancels reactor and cascades
	// All relations, callbacks, and values cleared
	cancel (final) {
		return this[_cancel](final, false);
	}

	// Sets new parent (or null) and recalculates value if req'd
	// Returns new parent
	attach (par) {
		if (this[_parent] !== par) {
			if (this[_parent] !== null) {
				// Remove from parent's child set
				this.detach();
			}
			if (par instanceof Reactor) {
				// Set new parent, add this to new parent's child set, and recalculate value
				this[_parent] = par[_addchild](this);
				// Will invoke setter and thus cascade if appropriate
				this.set(par.get());
			}
		}
		return this[_parent];
	}

	// Removes from parent's child set and nulls parent
	// Returns old parent
	detach (skipdel) {
		if ((!skipdel) && (this[_parent] !== null)) {
			this[_parent][_delchild](this);
		}
		// Clear parent regardless
		var par = this[_parent];
		this[_parent] = null;
		return par;
	}

	/*
		Private(ish) methods
	*/

	// Adds child to set
	[_addchild] (child) {
		this[_children].add(child);
		return this;
	}

	// Removes child from set
	[_delchild] (child) {
		// Error if child not in set
		// TODO: make this silent failure instead?
		if (!(this[_children].delete(child))) {
			throw new Error("Child not in set when _delchild() called: " + child.toString);
		}
		return this;
	}

	// Internal portion of cancel()
	[_cancel] (final, skipdel) {
		// If finalfunc is set, will be called with (final, value) before
		// passing result downward
		var finalval = (this[_finally] !== null) ? this[_finally](final, this[_value]) : final;
		// Reset finalval to val if _finally() returned undefined
		finalval = (finalval !== undefined) ? finalval : final;

		// Cascade to children (set skipdel to true regardless of passed arg)
		this[_children].forEach(child => child[_cancel](finalval, true));

		// Clear children
		this[_children].clear();

		// Clear parent
		// If skipdel is true, won't call delchild() on parent
		// (so parent can clean its own child set after cascading)
		this.detach(skipdel);

		// Clear value, thenfunc, finalfunc
		this[_value] = null;
		this[_then] = null;
		this[_finally] = null;

		// Done
		return finalval;
	}
}

export function cr (initval) {
	return new Reactor(initval);
}

<|endoftext|>


<commit_before>/**
 * Created by LiuyinC on 10/25/15.
 */
function main(rawData) {
  var aggData = aggregate(rawData);
  draw(rawData, aggData);
}

/**
 * get statistics of the data
 * @param data
 * @returns {*[]}
 */
function aggregate(data) {
  var result = [
    {
      key: '1',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    },
    {
      key: '2',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    },
    {
      key: '3',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    }
  ];

  data.forEach(function(d) {
    // get passenger class in result
    var pclass = result.filter(function(pclass) {
      return pclass.key == d.Pclass;
    })[0];
    // get gender in the above Pclass
    var sex = pclass.value.filter(function(sex) {
      return sex.key == d.Sex;
    })[0];
    // get total count in the above gender
    var total = sex.value.filter(function(e) {
      return e.key == 'total';
    })[0];
    // get survived count in the above gender
    var survived = sex.value.filter(function(e) {
      return e.key == 'survived';
    })[0];
    // increment the total count and survived count
    total.value ++;
    survived.value += +d.Survived;
  });

  return result;
}

function draw(rawData, aggData) {
  var width = 1000;
  var barHeight = 40;
  var gutter = 5;
  var pclassLabelWidth = 170;
  var genderLabelWidth = 70;
  var height = barHeight * 6; // total 6 bars

  var x = d3.scale.linear().domain([0, rawData.length]).range([0, width]);

  var chart = d3.select(".chart").attr("width", width).attr("height", height);

  var pclass = chart.selectAll("g")
    .data(aggData)
    .enter()
    .append("g")
    // have to use transform because g tag doesn't have x y dx dy attributes
    .attr("transform", function(d, i) { return "translate(0," + i * d.value.length * barHeight + ")"; });

  var pclassLabel = pclass.append("text")
    .text(function(d) { return "Passenger class " + d.key; })
    .attr('y', barHeight);

  var sex = pclass.selectAll('g')
    .data(function(d) { return d.value; })
    .enter()
    .append('g')
    // have to use transform because g tag doesn't have x y dx dy attributes
    .attr('transform', function(d, i) { return 'translate(' + pclassLabelWidth + ', ' + i * barHeight + ')'; });

  var sexLabel = sex.append('text')
    .text(function(d) { return d.key; })
    .attr('x', gutter)
    .attr('y', barHeight / 2);

  sex.selectAll('rect')
    .data(function(d) { return d.value; })
    .enter()
    .append('rect')
    .attr('width', function(d) { return x(d.value); })
    .attr('height', barHeight - gutter)
    .attr('class', function(d) { return d.key; })
    .attr('x', genderLabelWidth);

  sex.append("text")
    .attr("x", function(d) {
      var total = d.value.filter(function(e) {
        return e.key == 'total';
      })[0].value;
      return x(total + gutter) + genderLabelWidth;
    })
    .attr('text-anchor', 'start')
    .attr("y", barHeight / 2)
    .attr("dy", ".35em")
    .text(function(d) {
      var total = d.value.filter(function(e) {
        return e.key == 'total';
      })[0].value;
      var survived = d.value.filter(function(e) {
        return e.key == 'survived';
      })[0].value;
      var text = survived.toString() + '/' + total.toString();
      return text;
    });
}

d3.csv('data/train.csv', main);<commit_msg>added legends<commit_after>/**
 * Created by LiuyinC on 10/25/15.
 */
function main(rawData) {
  var aggData = aggregate(rawData);
  draw(rawData, aggData);
}

/**
 * get statistics of the data
 * @param data
 * @returns {*[]}
 */
function aggregate(data) {
  var result = [
    {
      key: '1',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    },
    {
      key: '2',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    },
    {
      key: '3',
      value: [
        {
          key: 'female',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        },
        {
          key: 'male',
          value: [
            {
              key: 'total',
              value: 0
            },
            {
              key: 'survived',
              value: 0
            }
          ]
        }
      ]
    }
  ];

  data.forEach(function(d) {
    // get passenger class in result
    var pclass = result.filter(function(pclass) {
      return pclass.key == d.Pclass;
    })[0];
    // get gender in the above Pclass
    var sex = pclass.value.filter(function(sex) {
      return sex.key == d.Sex;
    })[0];
    // get total count in the above gender
    var total = sex.value.filter(function(e) {
      return e.key == 'total';
    })[0];
    // get survived count in the above gender
    var survived = sex.value.filter(function(e) {
      return e.key == 'survived';
    })[0];
    // increment the total count and survived count
    total.value ++;
    survived.value += +d.Survived;
  });

  return result;
}

function draw(rawData, aggData) {
  var width = 1000;
  var barHeight = 40;
  var gutter = 5;
  var pclassLabelWidth = 170;
  var genderLabelWidth = 70;
  var height = barHeight * 6; // total 6 bars

  var x = d3.scale.linear().domain([0, rawData.length]).range([0, width]);

  var chart = d3.select(".chart").attr("width", width).attr("height", height);

  var pclass = chart.selectAll("g")
    .data(aggData)
    .enter()
    .append("g")
    // have to use transform because g tag doesn't have x y dx dy attributes
    .attr("transform", function(d, i) { return "translate(0," + i * d.value.length * barHeight + ")"; });

  var pclassLabel = pclass.append("text")
    .text(function(d) { return "Passenger class " + d.key; })
    .attr('y', barHeight);

  var sex = pclass.selectAll('g')
    .data(function(d) { return d.value; })
    .enter()
    .append('g')
    // have to use transform because g tag doesn't have x y dx dy attributes
    .attr('transform', function(d, i) { return 'translate(' + pclassLabelWidth + ', ' + i * barHeight + ')'; });

  var sexLabel = sex.append('text')
    .text(function(d) { return d.key; })
    .attr('x', gutter)
    .attr('y', barHeight / 2);

  sex.selectAll('rect')
    .data(function(d) { return d.value; })
    .enter()
    .append('rect')
    .attr('width', function(d) { return x(d.value); })
    .attr('height', barHeight - gutter)
    .attr('class', function(d) { return d.key; })
    .attr('x', genderLabelWidth);

  sex.append("text")
    .attr("x", function(d) {
      var total = d.value.filter(function(e) {
        return e.key == 'total';
      })[0].value;
      return x(total + gutter) + genderLabelWidth;
    })
    .attr('text-anchor', 'start')
    .attr("y", barHeight / 2)
    .attr("dy", ".35em")
    .text(function(d) {
      var total = d.value.filter(function(e) {
        return e.key == 'total';
      })[0].value;
      var survived = d.value.filter(function(e) {
        return e.key == 'survived';
      })[0].value;
      var text = survived.toString() + '/' + total.toString();
      return text;
    });

  var legends = chart.append('g')
    .attr('class', 'legends')
    .attr('transform', 'translate(550, 0)');

  var survivedLegend = legends.append('g');

  var survivedLegendRect = survivedLegend.append('rect')
    .attr('width', 40)
    .attr('height', 20)
    .attr('class', 'survived');
  var survivedLegendLabel = survivedLegend.append('text')
    .text('survived')
    .attr('x', 45)
    .attr('y', 16);

  var totalLegend = legends.append('g')
    .attr('transform', 'translate(0, 25)');

  var totalLegendRect = totalLegend.append('rect')
    .attr('width', 40)
    .attr('height', 20)
    .attr('class', 'total');

  var totalLegendLabel = totalLegend.append('text')
    .text('not survived')
    .attr('x', 45)
    .attr('y', 16);

}

d3.csv('data/train.csv', main);<|endoftext|>


<commit_before>/**
 * Corus JS Client
 * Copyright (c) 2016 Corus.io <juancarlos.vinas@corus.io>
 * MIT Licensed
 */

/*
 * Requires
 */

var request = require('request');
var WebSocket = require('ws');
var events = require('events');
var assign = require('object-assign');
var querystring = require('querystring');
var util = require('util');

/**
 * HttpError
 */

var HttpError = function(statusCode, message){

    Error.call(this);

    this.message = message || 'Unknown error';

    this.statusCode = statusCode || 500;

};

/**
 * Private Methods
 */

var requestInvokeFn = function(options){

    return function(bodyOrFilter, callback){

        if(!callback){

            callback = bodyOrFilter;
            bodyOrFilter = null;

        }

        if(!callback){

            callback = function(){};

        }

        if(bodyOrFilter) {

            if (options.method === 'POST' || options.method === 'PUT') {

                options = assign({}, options, {json: true, body: bodyOrFilter});

            } else {

                var filter = assign({}, bodyOrFilter);

                if(filter.where){

                    filter.where = JSON.stringify(filter.where);

                }

                if(filter.aggregation){

                    filter.aggregation = JSON.stringify(filter.aggregation);

                }

                if(filter.groupBy){

                    filter.groupBy = JSON.stringify(filter.groupBy);

                }

                options.url += '?' + querystring.stringify(filter);

            }

        }

        request(options, function(err, response, body){

            if(err){

                callback(err);

            } else if(response.statusCode < 200 || response.statusCode >= 400) {

                callback(new HttpError(response.statusCode, body));

            } else {

                var jsonBody = body;

                try { jsonBody = JSON.parse(body); } catch(e){}

                callback(null, jsonBody);

            }

            //Limpiamos el callback para evitar leaks de memoria

            callback = null;
            return;

        });

    };

};

var checkCredentials = function(headers){

    if(!headers.key){

        throw new Error('Invalid credentials');

    }

};

var pushInvokeFn = function(options, filter){

    return function(notification, callback){

        var body = {

            notification: notification,
            filter: filter

        };

        options = assign({}, options, {method: 'POST', json: true, body: body});

        request(options, function(err, response, body){

            if(err){

                callback(err);

            } else if(response.statusCode < 200 || response.statusCode >= 400) {

                callback(new HttpError(response.statusCode, body));

            } else {

                var jsonBody = body;

                try { jsonBody = JSON.parse(body); } catch(e){}

                callback(null, jsonBody);

            }

            //Limpiamos el callback para evitar leaks de memoria

            callback = null;
            return;

        });

    }

};

/**
 * Constructor
 *
 * @param options
 * Must contain a "host" property (ex: http://mycorp.corus.io)
 * Can contain a "key" property. If not supplied, then we must invoke "login" before any other method.
 */

var Corus = function(options){

    /**
     * Private Properties
     */

    var baseUrl = 'http://';
    var baseChannelsUrl = 'http://';
    var baseWSUrl = 'ws://';

    var baseHeaders = {};

    /**
     * Check Options
     */

    if(!options){

        throw new Error('options json is required');

    }

    if(!options.host){

        throw new Error('options must contain a "host" property');

    } else {

        baseUrl += options.host + '/api/v1';
        baseChannelsUrl += options.host;
        baseWSUrl += options.host;

    }

    if(options.key){

        baseHeaders.key = options.key;

    }

    if(options.lang){

        baseHeaders.lang = options.lang;

        if(options.fillWithDefaultLang){

            baseHeaders['fill-with-default-lang'] = 'true';

        }

    }

    if(options.avoidTrigger){

        // avoid-trigger: To avoid infinete recursive loops when invoking collection's data methods.

        baseHeaders['avoid-trigger'] = 'true';

    }

    /**
     * Login
     */

    this.login = function(emailAndPassword, callback){

        var url = baseUrl + '/me';

        var options = {

            url: url,
            headers: {
                authorization: 'Basic ' + new Buffer(emailAndPassword.email + ":" + emailAndPassword.password).toString('base64')
            }

        };

        requestInvokeFn(options)(function(err, user){

            if(!callback){

                callback = function(){};

            }

            if(err){

                return callback(err);

            } else {

                if(!baseHeaders.key) {

                    baseHeaders.key = user.key;

                }

                return callback(null, user);

            }

        });

    };

    /**
     * Users
     */

    this.users = function(user){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var url = baseUrl + '/users';
        var headers = assign({}, baseHeaders);

        if(!user){

            return {

                //POST ==> /users

                post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                //GET ==> /users

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

            }

        } else {

            url += '/' + user;

            return {

                //GET ==> /apps/:user

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                //PUT ==> /apps/:user

                put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                //DELETE ==> /apps/:user

                delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                /**
                 * Apps
                 */

                apps: function(app){

                    url += '/apps';

                    if(!app){

                        throw new Error('Invalid app');

                    } else {

                        url += '/' + app;

                        return {

                            //GET ==> /users/:users/apps/:app

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //PUT ==> /users/:users/apps/:app

                            put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                            //DELETE ==> /users/:users/apps/:app

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers})
                        }

                    }

                }

            }

        }

    };

    /**
     * Apps
     */

    this.apps = function(app){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var url = baseUrl + '/apps';
        var headers = assign({}, baseHeaders);

        if(!app){

            return {

                //POST ==> /apps

                post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                //GET ==> /apps

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

            }

        } else {

            url += '/' + app;

            return {

                //GET ==> /apps/:app

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                //PUT ==> /apps/:app

                put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                //DELETE ==> /apps/:app

                delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                /**
                 * Collections
                 */

                collections: function(collection){

                    url += '/collections';

                    if(!collection){

                        return {

                            //POST ==> /apps/:app/collections

                            post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                            //GET ==> /apps/:app/collections

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                        }

                    } else {

                        url += '/' + collection;

                        return {

                            //GET ==> /apps/:app/collections/:collection

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //PUT ==> /apps/:app/collections/:collection

                            put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                            //DELETE ==> /apps/:app/collections/:collection

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                            /**
                             * Data
                             */

                            data: function(id){

                                url += '/data';

                                if(!id){

                                    return {

                                        //POST ==> /apps/:app/collections/:collection/data

                                        post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                                        //GET ==> /apps/:app/collections/:collection/data

                                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                                    }

                                } else {

                                    url += '/' + id;

                                    return {

                                        //GET ==> /apps/:app/collections/:collection/data/:id

                                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                                        //PUT ==> /apps/:app/collections/:collection/data/:id

                                        put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                                        //DELETE ==> /apps/:app/collections/:collection/data/:id

                                        delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                                    }

                                }

                            }

                        }

                    }

                },

                /**
                 * Users
                 */

                users: function(email){

                    var pushUrl = url + '/push';
                    url += '/users';

                    return {

                        //GET ==> /apps/:app/users

                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                        //POST ==> /apps/:app/push

                        push: pushInvokeFn({url: pushUrl, headers: headers}, {where: {createdBy: email}})

                    }

                },

                /**
                 * Installations
                 */

                installations: function(device){

                    var pushUrl = url + '/push';
                    url += '/installations';

                    if(!device){

                        return {

                            //POST ==> /apps/:app/installations

                            post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                            //POST ==> /apps/:app/push

                            push: function(notification, where, callback){

                                pushInvokeFn({url: pushUrl, headers: headers}, {where: where})(notification, callback);

                            }

                        }

                    } else {

                        url += '/' + device;

                        return {

                            //GET ==> /apps/:app/installations/:device

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //DELETE ==> /apps/:app/installations/:device

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                            //POST ==> /apps/:app/push

                            push: pushInvokeFn({url: pushUrl, headers: headers}, {where: {device: device}})

                        }

                    }

                }

            }

        }

    };

    /**
     * Channels
     */

    this.channels = function(app){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var wsUrl = baseWSUrl + '/channels';
        var url = baseChannelsUrl + '/channels';
        var headers = assign({}, baseHeaders);

        if(!app) {

            throw new Error('Invalid app');

        } else if(!headers.key){

            throw new Error('Invalid user key');

        } else {

            url += '/' + app;
            wsUrl += '/' + app + '?key=' + headers.key;

            return {

                connect: function(){

                    var ws = new WebSocket(wsUrl);
                    var eventEmitter = new events.EventEmitter();

                    /**
                     * WS Events
                     */

                    ws.on('open', function(){

                        setTimeout(function(){

                            eventEmitter.emit('connected');

                        }, 500);

                    });

                    ws.on('error', function(err){

                        eventEmitter.emit('error', new Error('WS Error: ' + err.toString()));

                    });

                    ws.on('message', function(data){

                        var json  = null;

                        try { json = JSON.parse(data) } catch(e) { };

                        if(!json){

                            eventEmitter.emit('error', new Error('Invalid message'));

                        } else if(json.err){

                            eventEmitter.emit('error', json.err);

                        } else {

                            eventEmitter.emit('message', json.message);

                        }

                    });

                    /**
                     * Send Method
                     */

                    eventEmitter.send = function(to, data){

                        if(!to){

                            throw new Error('"to" parameter is required')

                        }

                        if(!data){

                            throw new Error('"data" parameter is required')

                        }

                        var jsonStr = JSON.stringify({

                            to: to,
                            data: data

                        });

                        ws.send(jsonStr);

                    };

                    return eventEmitter;

                },

                post: requestInvokeFn({method: 'POST', url: url, headers: headers})

            }

        }

    };

};

/**
 * Export
 */

module.exports = Corus;

<commit_msg>no message<commit_after>/**
 * Corus JS Client
 * Copyright (c) 2016 Corus.io <juancarlos.vinas@corus.io>
 * MIT Licensed
 */

/*
 * Requires
 */

var request = require('request');
var WebSocket = require('ws');
var events = require('events');
var assign = require('object-assign');
var querystring = require('querystring');
var util = require('util');

/**
 * HttpError
 */

var HttpError = function(statusCode, message){

    Error.call(this);

    this.message = message || 'Unknown error';

    this.statusCode = statusCode || 500;

};

/**
 * Private Methods
 */

var requestInvokeFn = function(options){

    return function(bodyOrFilter, callback){

        if(!callback){

            callback = bodyOrFilter;
            bodyOrFilter = null;

        }

        if(!callback){

            callback = function(){};

        }

        if(bodyOrFilter) {

            if (options.method === 'POST' || options.method === 'PUT') {

                options = assign({}, options, {json: true, body: bodyOrFilter});

            } else {

                var filter = assign({}, bodyOrFilter);

                if(filter.where){

                    filter.where = JSON.stringify(filter.where);

                }

                if(filter.aggregation){

                    filter.aggregation = JSON.stringify(filter.aggregation);

                }

                if(filter.groupBy){

                    filter.groupBy = JSON.stringify(filter.groupBy);

                }

                options.url += '?' + querystring.stringify(filter);

            }

        }

        request(options, function(err, response, body){

            if(err){

                callback(err);

            } else if(response.statusCode < 200 || response.statusCode >= 400) {

                callback(new HttpError(response.statusCode, body));

            } else {

                var jsonBody = body;

                try { jsonBody = JSON.parse(body); } catch(e){}

                callback(null, jsonBody);

            }

            //Limpiamos el callback para evitar leaks de memoria

            callback = null;
            return;

        });

    };

};

var checkCredentials = function(headers){

    if(!headers.key){

        throw new Error('Invalid credentials');

    }

};

var pushInvokeFn = function(options, filter){

    return function(notification, callback){

        var body = {

            notification: notification,
            filter: filter

        };

        options = assign({}, options, {method: 'POST', json: true, body: body});

        request(options, function(err, response, body){

            if(err){

                callback(err);

            } else if(response.statusCode < 200 || response.statusCode >= 400) {

                callback(new HttpError(response.statusCode, body));

            } else {

                var jsonBody = body;

                try { jsonBody = JSON.parse(body); } catch(e){ }

                callback(null, jsonBody);

            }

            //Limpiamos el callback para evitar leaks de memoria

            callback = null;
            return;

        });

    }

};

/**
 * Constructor
 *
 * @param options
 * Must contain a "host" property (ex: http://mycorp.corus.io)
 * Can contain a "key" property. If not supplied, then we must invoke "login" before any other method.
 */

var Corus = function(options){

    /**
     * Private Properties
     */

    var baseUrl = 'http://';
    var baseChannelsUrl = 'http://';
    var baseWSUrl = 'ws://';

    var baseHeaders = {};

    /**
     * Check Options
     */

    if(!options){

        throw new Error('options json is required');

    }

    if(!options.host){

        throw new Error('options must contain a "host" property');

    } else {

        baseUrl += options.host + '/api/v1';
        baseChannelsUrl += options.host;
        baseWSUrl += options.host;

    }

    if(options.key){

        baseHeaders.key = options.key;

    }

    if(options.lang){

        baseHeaders.lang = options.lang;

        if(options.fillWithDefaultLang){

            baseHeaders['fill-with-default-lang'] = 'true';

        }

    }

    if(options.avoidTrigger){

        // avoid-trigger: To avoid infinete recursive loops when invoking collection's data methods.

        baseHeaders['avoid-trigger'] = 'true';

    }

    /**
     * Login
     */

    this.login = function(emailAndPassword, callback){

        var url = baseUrl + '/me';

        var options = {

            url: url,
            headers: {
                authorization: 'Basic ' + new Buffer(emailAndPassword.email + ":" + emailAndPassword.password).toString('base64')
            }

        };

        requestInvokeFn(options)(function(err, user){

            if(!callback){

                callback = function(){};

            }

            if(err){

                return callback(err);

            } else {

                if(!baseHeaders.key) {

                    baseHeaders.key = user.key;

                }

                return callback(null, user);

            }

        });

    };

    /**
     * Users
     */

    this.users = function(user){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var url = baseUrl + '/users';
        var headers = assign({}, baseHeaders);

        if(!user){

            return {

                //POST ==> /users

                post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                //GET ==> /users

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

            }

        } else {

            url += '/' + user;

            return {

                //GET ==> /apps/:user

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                //PUT ==> /apps/:user

                put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                //DELETE ==> /apps/:user

                delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                /**
                 * Apps
                 */

                apps: function(app){

                    url += '/apps';

                    if(!app){

                        throw new Error('Invalid app');

                    } else {

                        url += '/' + app;

                        return {

                            //GET ==> /users/:users/apps/:app

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //PUT ==> /users/:users/apps/:app

                            put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                            //DELETE ==> /users/:users/apps/:app

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers})
                        }

                    }

                }

            }

        }

    };

    /**
     * Apps
     */

    this.apps = function(app){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var url = baseUrl + '/apps';
        var headers = assign({}, baseHeaders);

        if(!app){

            return {

                //POST ==> /apps

                post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                //GET ==> /apps

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

            }

        } else {

            url += '/' + app;

            return {

                //GET ==> /apps/:app

                get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                //PUT ==> /apps/:app

                put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                //DELETE ==> /apps/:app

                delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                /**
                 * Collections
                 */

                collections: function(collection){

                    url += '/collections';

                    if(!collection){

                        return {

                            //POST ==> /apps/:app/collections

                            post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                            //GET ==> /apps/:app/collections

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                        }

                    } else {

                        url += '/' + collection;

                        return {

                            //GET ==> /apps/:app/collections/:collection

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //PUT ==> /apps/:app/collections/:collection

                            put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                            //DELETE ==> /apps/:app/collections/:collection

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                            /**
                             * Data
                             */

                            data: function(id){

                                url += '/data';

                                if(!id){

                                    return {

                                        //POST ==> /apps/:app/collections/:collection/data

                                        post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                                        //GET ==> /apps/:app/collections/:collection/data

                                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                                    }

                                } else {

                                    url += '/' + id;

                                    return {

                                        //GET ==> /apps/:app/collections/:collection/data/:id

                                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                                        //PUT ==> /apps/:app/collections/:collection/data/:id

                                        put: requestInvokeFn({method: 'PUT', url: url, headers: headers}),

                                        //DELETE ==> /apps/:app/collections/:collection/data/:id

                                        delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                                    }

                                }

                            }

                        }

                    }

                },

                /**
                 * Users
                 */

                users: function(email){

                    var pushUrl = url + '/push';
                    url += '/users';

                    return {

                        //GET ==> /apps/:app/users

                        get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                        //POST ==> /apps/:app/push

                        push: pushInvokeFn({url: pushUrl, headers: headers}, {where: {createdBy: email}})

                    }

                },

                /**
                 * Installations
                 */

                installations: function(device){

                    var pushUrl = url + '/push';
                    url += '/installations';

                    if(!device){

                        return {

                            //POST ==> /apps/:app/installations

                            post: requestInvokeFn({method: 'POST', url: url, headers: headers}),

                            //POST ==> /apps/:app/push

                            push: function(notification, where, callback){

                                pushInvokeFn({url: pushUrl, headers: headers}, {where: where})(notification, callback);

                            }

                        }

                    } else {

                        url += '/' + device;

                        return {

                            //GET ==> /apps/:app/installations/:device

                            get: requestInvokeFn({method: 'GET', url: url, headers: headers}),

                            //DELETE ==> /apps/:app/installations/:device

                            delete: requestInvokeFn({method: 'DELETE', url: url, headers: headers}),

                            //POST ==> /apps/:app/push

                            push: pushInvokeFn({url: pushUrl, headers: headers}, {where: {device: device}})

                        }

                    }

                }

            }

        }

    };

    /**
     * Channels
     */

    this.channels = function(app){

        //Check if we have a valid "key"
        checkCredentials(baseHeaders);

        var wsUrl = baseWSUrl + '/channels';
        var url = baseChannelsUrl + '/channels';
        var headers = assign({}, baseHeaders);

        if(!app) {

            throw new Error('Invalid app');

        } else if(!headers.key){

            throw new Error('Invalid user key');

        } else {

            url += '/' + app;
            wsUrl += '/' + app + '?key=' + headers.key;

            return {

                connect: function(){

                    var ws = new WebSocket(wsUrl);
                    var eventEmitter = new events.EventEmitter();

                    /**
                     * WS Events
                     */

                    ws.on('open', function(){

                        setTimeout(function(){

                            eventEmitter.emit('connected');

                        }, 500);

                    });

                    ws.on('error', function(err){

                        eventEmitter.emit('error', new Error('WS Error: ' + err.toString()));

                    });

                    ws.on('message', function(data){

                        var json  = null;

                        try { json = JSON.parse(data) } catch(e) { };

                        if(!json){

                            eventEmitter.emit('error', new Error('Invalid message'));

                        } else if(json.err){

                            eventEmitter.emit('error', json.err);

                        } else {

                            eventEmitter.emit('message', json.message);

                        }

                    });

                    /**
                     * Send Method
                     */

                    eventEmitter.send = function(to, data){

                        if(!to){

                            throw new Error('"to" parameter is required')

                        }

                        if(!data){

                            throw new Error('"data" parameter is required')

                        }

                        var jsonStr = JSON.stringify({

                            to: to,
                            data: data

                        });

                        ws.send(jsonStr);

                    };

                    return eventEmitter;

                },

                post: requestInvokeFn({method: 'POST', url: url, headers: headers})

            }

        }

    };

};

/**
 * Export
 */

module.exports = Corus;

<|endoftext|>


<commit_before>$(document).ready(function(){
	var thisVideo_1 = document.getElementById("video_1");
	var thisVideo_2 = document.getElementById("video_2");
	var thisVideo_3 = document.getElementById("video_3");
	var thisVideo_4 = document.getElementById("video_4");
	var thisVideo_5 = document.getElementById("video_5");
	var thisVideo_6 = document.getElementById("video_6");
	var thisVideo_7 = document.getElementById("video_7");

	if(thisVideo_1){
		thisVideo_1.addEventListener('pause',function(){
			$(".hide_video_1").hide();
		})
		thisVideo_2.addEventListener('pause',function(){
			$(".hide_video_2").hide();
		})
		thisVideo_3.addEventListener('pause',function(){
			$(".hide_video_3").hide();
		})
		thisVideo_4.addEventListener('pause',function(){
			$(".hide_video_4").hide();
		})
		thisVideo_5.addEventListener('pause',function(){
			$(".hide_video_5").hide();
		})
		thisVideo_6.addEventListener('pause',function(){
			$(".hide_video_6").hide();
		})
		thisVideo_7.addEventListener('pause',function(){
			$(".hide_video_7").hide();
		})
	}

	$(".car_detail .video_1").click(function(){
		$(".hide_video_1").show();
		thisVideo_1.play();
		return false;
	});
	$(".car_detail .video_2").click(function(){
		$(".hide_video_2").show();
		thisVideo_2.play();
		return false;
	});
	$(".car_detail .video_3").click(function(){
		$(".hide_video_3").show();
		thisVideo_3.play();
		return false;
	});
	$(".car_detail .video_4").click(function(){
		$(".hide_video_4").show();
		thisVideo_4.play();
		return false;
	});
	$(".car_detail .video_5").click(function(){
		$(".hide_video_5").show();
		thisVideo_5.play();
		return false;
	});
	$(".car_detail .video_6").click(function(){
		$(".hide_video_6").show();
		thisVideo_6.play();
		return false;
	});
	$(".car_detail .video_7").click(function(){
		$(".hide_video_7").show();
		thisVideo_7.play();
		return false;
	});
});
<commit_msg>bug修护<commit_after>$(document).ready(function(){
	var thisVideo_1 = document.getElementById("video_1");
	var thisVideo_2 = document.getElementById("video_2");
	var thisVideo_3 = document.getElementById("video_3");

	if(thisVideo_1){
		thisVideo_1.addEventListener('pause',function(){
			$(".hide_video_1").hide();
		})
		thisVideo_2.addEventListener('pause',function(){
			$(".hide_video_2").hide();
		})
		thisVideo_3.addEventListener('pause',function(){
			$(".hide_video_3").hide();
		})
	}

	$(".car_detail .video_1").click(function(){
		$(".hide_video_1").show();
		thisVideo_1.play();
		return false;
	});
	$(".car_detail .video_2").click(function(){
		$(".hide_video_2").show();
		thisVideo_2.play();
		return false;
	});
	$(".car_detail .video_3").click(function(){
		$(".hide_video_3").show();
		thisVideo_3.play();
		return false;
	});
});
<|endoftext|>


<commit_before>/*! KarusellenJS: an easy to use vanillaJS carousel. Copyright 2015 @utegard. Licensed MIT */

;(function(window, undefined){
	'use strict';

	var Karusellen = window.Karusellen || {};

	Karusellen = function(options){

		var _settings = {
			karusellenClass: 'karusellen',
			karusellenContentClass: 'karusellen-content',
			karusellenItemClass: 'karusellen-content__item',
			itemsToShow: 2,
			itemFloatDirection: 'left',
			buttonClass: 'kursellen__button',
			prevButtonClass: 'kursellen__button--prev',
			prevButtonInnerHTML: 'Previous Slide',
			nextButtonClass: 'kursellen__button--next',
			nextButtonInnerHTML: 'Next Slide'
		};

		Object.defineProperty(this, 'settings', {

			get: function(){
				return _settings;
			},
			set: function(settingsObject){

				if(typeof settingsObject !== 'object'){
					throw new Error('settings is not an object');
				}
				_settings = settingsObject;
			}

		});

		if(options && typeof options === 'object'){
			this.settings = squash(this.settings, options);
		}

		this.init();
	};

	Karusellen.prototype = {

		init: function(){
			this.loadCarousel();
		},

		loadCarousel: function(){

			var self = this;
			var carouselItems = document.getElementsByClassName(this.settings.karusellenClass);

			[].forEach.call(carouselItems, function(carousel){

				var referenceObj = {
					original: carousel,
					clone: carousel.cloneNode(true)
				};

				new MerryGoRound(referenceObj, self.settings);

			});
		}
	};

	var MerryGoRound = function(_referenceObj, _settings){

		Object.defineProperty(this, 'settings', {

			get: function(){
				return _settings;
			},
			set: function(settingsObject){

				if(typeof settingsObject !== 'object'){
					throw new Error('settings is not an object');
				}
				_settings = settingsObject;
			}

		});

		Object.defineProperty(this, 'referenceObj', {

			get: function(){
				return _referenceObj;
			},
			set: function(referenceObj){

				if(typeof referenceObj !== 'object'){
					throw new Error('settings is not an object');
				}
				_referenceObj = referenceObj;
			}

		});

		this.init();
	};

	MerryGoRound.prototype = {

		init: function(){
			this.defineProps();
			this.scaffold();
		},

		defineProps: function(){

			var _currentSlide = 0,
				_amountOfItems = this.referenceObj.clone.children.length,
				_hasTouchSupport = (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);

			Object.defineProperty(this, 'hasTouchSupport', {

				get: function(){
					return _hasTouchSupport;
				},
				set: function(value){
					_hasTouchSupport = value;
				}

			});

			Object.defineProperty(this, 'currentSlide', {

				get: function(){
					return _currentSlide;
				},
				set: function(value){
					var intVal = parseInt(value, 10);
					if(isNaN(intVal)){
						throw new Error('currentSlide must be an integer');
					}
					_currentSlide = value;
				}

			});

			Object.defineProperty(this, 'amountOfItems', {

				get: function(){
					return _amountOfItems;
				},
				set: function(value){
					var intVal = parseInt(value, 10);
					if(isNaN(intVal) || intVal < 1){
						throw new Error('amountOfItems must be an integer');
					}
					_amountOfItems = value;
				}

			});
		},

		scaffold: function(){
			var self = this,
				fragment = document.createDocumentFragment(),
				nodeType = this.referenceObj.clone.nodeName.toLowerCase(),
				karusellenList = null;

			if(nodeType === 'ul' || nodeType === 'ol'){
				karusellenList = document.createElement('li');
				karusellenList.style.width = 100 + '%';
				this.karusellenContent = document.createElement(nodeType);
			}else{
				this.karusellenContent = document.createElement('div');
			}

			var size = this.getCarouselSizes(this.amountOfItems);
			this.karusellenContent.className = this.settings.karusellenContentClass;
			this.karusellenContent.style.width = size.carouselWidth + '%';

			[].slice.call(this.referenceObj.clone.children).map(function(item, index){

				if(item.hasAttribute('class')){
					item.className += ' ' + self.settings.karusellenItemClass;
				}else{
					item.className = self.settings.karusellenItemClass;
				}
				item.style.width = size.itemWidth + '%';
				item.style.float = self.settings.itemFloatDirection;

				self.karusellenContent.appendChild(item);
			});

			if(karusellenList === null){
				fragment.appendChild(this.karusellenContent);
			}else{
				karusellenList.appendChild(this.karusellenContent);
				fragment.appendChild(karusellenList);
			}

			if(this.hasTouchSupport !== true){
				var control = this.createControls();
				fragment.appendChild(control.prev);
				fragment.appendChild(control.next);
			}

			this.referenceObj.original.innerHTML = '';
			this.referenceObj.original.style.width = 100 + '%';

			if(this.hasTouchSupport){
				this.referenceObj.original.style.overflowX = 'auto';
				this.referenceObj.original.style.overflowY = 'hidden';
				this.referenceObj.original.style.WebkitOverflowScrolling = 'touch';
			}else{
				this.referenceObj.original.style.overflow = 'hidden';
			}

			this.referenceObj.original.appendChild(fragment);
		},

		createEvent: function(button){

			var self = this;

			button.addEventListener('click', function(){

				if(hasClass(this, self.settings.prevButtonClass)){
					self.updateIndex('prev');
				}else if(hasClass(this, self.settings.nextButtonClass)){
					self.updateIndex('next');
				}

			});
		},

		updateIndex: function(direction){

			switch(direction){

				case 'prev':
					if(this.currentSlide === 0){
						this.currentSlide = (this.amountOfItems - 1);
					}else{
						this.currentSlide = (this.currentSlide - 1);
					}
					break;
				case 'next':
					if(this.currentSlide === (this.amountOfItems - 1)){
						this.currentSlide = 0;
					}else{
						this.currentSlide = (this.currentSlide + 1);
					}
					break;
				default:
					throw new Error('direction is not valid');

			}
			this.makeItSpin();
		},

		makeItSpin: function(){
			var self = this,
				translateValue;

			if(this.currentSlide === 0){
				translateValue = 0;
			}else{
				translateValue = ((this.currentSlide/this.amountOfItems) * 100);
			}
			this.karusellenContent.style.webkitTransform = 'translateX(-'+translateValue+'%)';

		},

		getCarouselSizes: function(amountOfItems){

			var carouselWidth = ((100*amountOfItems)/this.settings.itemsToShow);
			var itemWidth = (100/amountOfItems);

			var size = {
				carouselWidth: carouselWidth,
				itemWidth: itemWidth
			}
			return size;
		},

		createControls: function(){
			var prevButton = document.createElement('button');
			var nextButton = document.createElement('button');
			prevButton.type = 'button';
			prevButton.className = this.settings.buttonClass+' '+this.settings.prevButtonClass;
			prevButton.innerHTML = this.settings.prevButtonInnerHTML;
			nextButton.type = 'button';
			nextButton.className = this.settings.buttonClass+' '+this.settings.nextButtonClass;
			nextButton.innerHTML = this.settings.nextButtonInnerHTML;

			this.createEvent(prevButton);
			this.createEvent(nextButton);

			var control = {
				prev: prevButton,
				next: nextButton
			}
			return control;
		}
	};

	var hasClass = function(element, classname){

		var classes = element.getAttribute("class").split(' '),
			regexp = new RegExp("\\b"+classname+"\\b"),
			hasclass = false;

			if(element.className.match(regexp)){
				hasclass = true;
			}
			return hasclass;
	};

	var squash = function(target, source){
		var targetObj = Object.create(target);
		Object.keys(source).map(function(property){
			property in targetObj && (targetObj[property] = source[property]);
		});
		return targetObj;
	};

	window.Karusellen = Karusellen;

}(this));<commit_msg>added prev and next buttons wrapper element<commit_after>/*! KarusellenJS: an easy to use vanillaJS carousel. Copyright 2015 @utegard. Licensed MIT */

;(function(window, undefined){
	'use strict';

	var Karusellen = window.Karusellen || {};

	Karusellen = function(options){

		var _settings = {
			karusellenClass: 'karusellen',
			karusellenContentClass: 'karusellen-content',
			karusellenItemClass: 'karusellen-content__item',
			itemsToShow: 2,
			itemFloatDirection: 'left',
			buttonsWrapperClass: 'karusellen-controls',
			buttonClass: 'karusellen-controls__button',
			prevButtonClass: 'karusellen-controls__button--prev',
			prevButtonInnerHTML: 'Previous Slide',
			nextButtonClass: 'karusellen-controls__button--next',
			nextButtonInnerHTML: 'Next Slide'
		};

		Object.defineProperty(this, 'settings', {

			get: function(){
				return _settings;
			},
			set: function(settingsObject){

				if(typeof settingsObject !== 'object'){
					throw new Error('settings is not an object');
				}
				_settings = settingsObject;
			}

		});

		if(options && typeof options === 'object'){
			this.settings = squash(this.settings, options);
		}

		this.init();
	};

	Karusellen.prototype = {

		init: function(){
			this.loadCarousel();
		},

		loadCarousel: function(){

			var self = this;
			var carouselItems = document.getElementsByClassName(this.settings.karusellenClass);

			[].forEach.call(carouselItems, function(carousel){

				var referenceObj = {
					original: carousel,
					clone: carousel.cloneNode(true)
				};

				new MerryGoRound(referenceObj, self.settings);

			});
		}
	};

	var MerryGoRound = function(_referenceObj, _settings){

		Object.defineProperty(this, 'settings', {

			get: function(){
				return _settings;
			},
			set: function(settingsObject){

				if(typeof settingsObject !== 'object'){
					throw new Error('settings is not an object');
				}
				_settings = settingsObject;
			}

		});

		Object.defineProperty(this, 'referenceObj', {

			get: function(){
				return _referenceObj;
			},
			set: function(referenceObj){

				if(typeof referenceObj !== 'object'){
					throw new Error('settings is not an object');
				}
				_referenceObj = referenceObj;
			}

		});

		this.init();
	};

	MerryGoRound.prototype = {

		init: function(){
			this.defineProps();
			this.scaffold();
		},

		defineProps: function(){

			var _currentSlide = 0,
				_amountOfItems = this.referenceObj.clone.children.length,
				_hasTouchSupport = (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);

			Object.defineProperty(this, 'hasTouchSupport', {

				get: function(){
					return _hasTouchSupport;
				},
				set: function(value){
					_hasTouchSupport = value;
				}

			});

			Object.defineProperty(this, 'currentSlide', {

				get: function(){
					return _currentSlide;
				},
				set: function(value){
					var intVal = parseInt(value, 10);
					if(isNaN(intVal)){
						throw new Error('currentSlide must be an integer');
					}
					_currentSlide = value;
				}

			});

			Object.defineProperty(this, 'amountOfItems', {

				get: function(){
					return _amountOfItems;
				},
				set: function(value){
					var intVal = parseInt(value, 10);
					if(isNaN(intVal) || intVal < 1){
						throw new Error('amountOfItems must be an integer');
					}
					_amountOfItems = value;
				}

			});
		},

		scaffold: function(){
			var self = this,
				fragment = document.createDocumentFragment(),
				nodeType = this.referenceObj.clone.nodeName.toLowerCase(),
				karusellenList = null;

			if(nodeType === 'ul' || nodeType === 'ol'){
				karusellenList = document.createElement('li');
				karusellenList.style.width = 100 + '%';
				this.karusellenContent = document.createElement(nodeType);
			}else{
				this.karusellenContent = document.createElement('div');
			}

			var size = this.getCarouselSizes(this.amountOfItems);
			this.karusellenContent.className = this.settings.karusellenContentClass;
			this.karusellenContent.style.width = size.carouselWidth + '%';

			[].slice.call(this.referenceObj.clone.children).map(function(item, index){

				if(item.hasAttribute('class')){
					item.className += ' ' + self.settings.karusellenItemClass;
				}else{
					item.className = self.settings.karusellenItemClass;
				}
				item.style.width = size.itemWidth + '%';
				item.style.float = self.settings.itemFloatDirection;

				self.karusellenContent.appendChild(item);
			});

			if(karusellenList === null){
				fragment.appendChild(this.karusellenContent);
			}else{
				karusellenList.appendChild(this.karusellenContent);
				fragment.appendChild(karusellenList);
			}

			if(this.hasTouchSupport !== true){

				var control = this.createControls(),
					controlWrapper;

				if(karusellenList === null){
					controlWrapper = document.createElement('div')
				}else{
					controlWrapper = document.createElement('li');
				}
				controlWrapper.className = this.settings.buttonsWrapperClass;
				controlWrapper.appendChild(control.prev);
				controlWrapper.appendChild(control.next);
				fragment.appendChild(controlWrapper);
			}

			this.referenceObj.original.innerHTML = '';
			this.referenceObj.original.style.width = 100 + '%';

			if(this.hasTouchSupport){
				this.referenceObj.original.style.overflowX = 'auto';
				this.referenceObj.original.style.overflowY = 'hidden';
				this.referenceObj.original.style.WebkitOverflowScrolling = 'touch';
			}else{
				this.referenceObj.original.style.overflow = 'hidden';
			}

			this.referenceObj.original.appendChild(fragment);
		},

		createEvent: function(button){

			var self = this;

			button.addEventListener('click', function(){

				if(hasClass(this, self.settings.prevButtonClass)){
					self.updateIndex('prev');
				}else if(hasClass(this, self.settings.nextButtonClass)){
					self.updateIndex('next');
				}

			});
		},

		updateIndex: function(direction){

			switch(direction){

				case 'prev':
					if(this.currentSlide === 0){
						this.currentSlide = (this.amountOfItems - 1);
					}else{
						this.currentSlide = (this.currentSlide - 1);
					}
					break;
				case 'next':
					if(this.currentSlide === (this.amountOfItems - 1)){
						this.currentSlide = 0;
					}else{
						this.currentSlide = (this.currentSlide + 1);
					}
					break;
				default:
					throw new Error('direction is not valid');

			}
			this.makeItSpin();
		},

		makeItSpin: function(){
			var self = this,
				translateValue;

			if(this.currentSlide === 0){
				translateValue = 0;
			}else{
				translateValue = ((this.currentSlide/this.amountOfItems) * 100);
			}
			this.karusellenContent.style.webkitTransform = 'translateX(-'+translateValue+'%)';

		},

		getCarouselSizes: function(amountOfItems){

			var carouselWidth = ((100*amountOfItems)/this.settings.itemsToShow);
			var itemWidth = (100/amountOfItems);

			var size = {
				carouselWidth: carouselWidth,
				itemWidth: itemWidth
			}
			return size;
		},

		createControls: function(){
			var prevButton = document.createElement('button');
			var nextButton = document.createElement('button');
			prevButton.type = 'button';
			prevButton.className = this.settings.buttonClass+' '+this.settings.prevButtonClass;
			prevButton.innerHTML = this.settings.prevButtonInnerHTML;
			nextButton.type = 'button';
			nextButton.className = this.settings.buttonClass+' '+this.settings.nextButtonClass;
			nextButton.innerHTML = this.settings.nextButtonInnerHTML;

			this.createEvent(prevButton);
			this.createEvent(nextButton);

			var control = {
				prev: prevButton,
				next: nextButton
			}
			return control;
		}
	};

	var hasClass = function(element, classname){

		var classes = element.getAttribute("class").split(' '),
			regexp = new RegExp("\\b"+classname+"\\b"),
			hasclass = false;

			if(element.className.match(regexp)){
				hasclass = true;
			}
			return hasclass;
	};

	var squash = function(target, source){
		var targetObj = Object.create(target);
		Object.keys(source).map(function(property){
			property in targetObj && (targetObj[property] = source[property]);
		});
		return targetObj;
	};

	window.Karusellen = Karusellen;

}(this));<|endoftext|>


<commit_before>// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");
    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);
$(document).ready(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
    $(this).closest('.collapse').collapse('toggle');
});

}<commit_msg>Trying to fix nav bar, changing JS code<commit_after>// jQuery to collapse the navbar on scroll
function collapseNavbar() {
    if ($(".navbar").offset().top >= 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");
    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
}

$(window).scroll(collapseNavbar);
$(document).ready(collapseNavbar);

// jQuery for page scrolling feature - requires jQuery Easing plugin
$(function() {
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
    $(this).closest('.collapse').collapse('toggle');
});

}<|endoftext|>


<commit_before>/**
 * Dependencies
 */
const logging = require('./logging');

/**
 * Individual Accelerator Packs
 */
let communication;
let textChat;
let screenSharing;
let annotation;
let archiving;

/**
 * Session, publishers, and subscribers
 */
// let session;
const publishers = new Set();
const subscribers = new Set();
const streams = new Set();

/**
 * Example options hash for init
 */
// const exampleOptions = {
//   credentials: {
//     apiKey: '123',
//     sessionId: '456',
//     token: 'tok123',
//   },
//   packages: ['textChat', 'screenSharing', 'annotation', 'archiving'],
//   communication: {

//   },
//   textChat: {

//   },
//   screenSharing: {

//   },
//   annotation: {

//   },
// };

/** Eventing */

const registeredEvents = {};

/**
 * Register events that can be listened to be other components/modules
 * @param {array | string} events - A list of event names. A single event may
 * also be passed as a string.
 * @returns {function} See triggerEvent
 */
const registerEvents = events => {
  const eventList = Array.isArray(events) ? events : [events];

  eventList.forEach(event => {
    if (!registeredEvents[event]) {
      registeredEvents[event] = new Set();
    }
  });
};

/**
 * Register a callback for a specific event
 * @param {String} event - The name of the event
 * @param {Function} callback
 */
const registerEventListener = (event, callback) => {
  const eventCallbacks = registeredEvents[event];
  if (!eventCallbacks) {
    logging.error(`${event} is not a registered event.`);
  } else {
    eventCallbacks.add(callback);
  }
};

/**
 * Trigger an event and fire all registered callbacks
 * @param {String} event - The name of the event
 * @param {*} data - Data to be passed to callback functions
 */
const triggerEvent = (event, data) => {
  const eventCallbacks = registeredEvents[event];
  if (!eventCallbacks) {
    registeredEvents(event);
    logging.log(`${event} has been registered as a new event.`);
  } else {
    eventCallbacks.forEach(callback => callback(data, event));
  }
};

/** Returns the current OpenTok session object */
// const getSession = () => session;
let getSession;

/** Returns the current OpenTok session credentials */
let getCredentials;

const createSessionEventListeners = session => {
  registerEvents(['streamCreated', 'streamDestroyed', 'error']);
  session.on({
    streamCreated(event) {
      streams.add(event.stream);
      triggerEvent('streamCreated', event.stream);
    },
    streamDestroyed(event) {
      streams.remove(event.stream);
      triggerEvent('streamDestroyed', event.stream);
    },
  });
};

const initPackages = (session, options) => {
  const env = typeof module === 'object' && typeof module.exports === 'object' ?
    'node' :
    'browser';

  const availablePackages = {
    textChat: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-text-chat'),
      browser: () => TextChatAccPack, // eslint-disable-line no-undef
    },
    screenSharing: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-screen-sharing'),
      browser: () => ScreenSharingAccPack, // eslint-disable-line no-undef
    },
    annotation: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-annotation'),
      browser: () => AnnotationAccPack, // eslint-disable-line no-undef
    },
    archiving: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-archiving'),
      browser: () => ArchivingAccPack, // eslint-disable-line no-undef
    },
  };
  const packages = {};
  options.packages.forEach((acceleratorPack) => {
    if (availablePackages[acceleratorPack]) { // eslint-disable-next-line no-param-reassign
      const packageName = `${acceleratorPack[0].toUpperCase()}${acceleratorPack.slice(1)}`;
      packages[packageName] = availablePackages[acceleratorPack][env]();
    } else {
      logging.log(`${acceleratorPack} is not a valid accelerator pack`);
    }
  });

  const packageOptions = packageName => {
    const accPack = { registerEvents, triggerEvent };
    return Object.assign({}, options[packageName], { session, accPack });
  };

  // eslint-disable-next-line global-require,import/no-extraneous-dependencies
  communication = require('./communication')(packageOptions('communication'));
  textChat = new packages.TextChat(packageOptions('textChat'));
  screenSharing = new packages.ScreenSharing(packageOptions('screenSharing'));
  annotation = new packages.Annotation(packageOptions('annotation'));
  archiving = new packages.Archiving(packageOptions('archiving'));
};

/**
 * Ensures that we have the required credentials
 * @param {Object} credentials
 * @param {String} credentials.apiKey
 * @param {String} credentials.sessionId
 * @param {String} credentials.token
 */
const validateCredentials = credentials => {
  const required = ['apiKey', 'sessionId', 'token'];
  required.forEach(credential => {
    if (!credentials[credential]) {
      logging.error(`${credential} is a required credential`);
    }
  });
};

/**
 * Connect to the session
 */
const connect = () => {
  const session = getSession();
  const { token } = getCredentials();
  session.connect(token);
};

/**
 * Initialize the accelerator pack
 * @param {Object} options
 * @param {Object} options.credentials
 */
const init = (options) => {
  if (!options) {
    logging.error('Missing options required for initialization');
  }
  const { credentials } = options;
  validateCredentials(credentials);
  const session = OT.initSession(credentials.apiKey, credentials.sessionId, error => {
    if (error) {
      logging.error(error);
    } else {
      initPackages(session, options);
      createSessionEventListeners(session);
      getSession = () => session;
      getCredentials = () => credentials;
    }
  });
};

module.exports = {
  init,
  connect,
  getSession,
  registeredEvents,
  registerEventListener,
  triggerEvent,
};
<commit_msg>Use plain objects for publishers and subscribers. Extend options for communication.<commit_after>/**
 * Dependencies
 */
const logging = require('./logging');

/**
 * Individual Accelerator Packs
 */
let communication;
let textChat;
let screenSharing;
let annotation;
let archiving;

/**
 * Session, publishers, and subscribers
 */
// let session;
const publishers = {
  camera: null,
  screen: null,
};
const subscribers = {};
const streams = {};

/**
 * Example options hash for init
 */
// const exampleOptions = {
//   credentials: {
//     apiKey: '123',
//     sessionId: '456',
//     token: 'tok123',
//   },
//   packages: ['textChat', 'screenSharing', 'annotation', 'archiving'],
//   communication: {

//   },
//   textChat: {

//   },
//   screenSharing: {

//   },
//   annotation: {

//   },
// };

/** Eventing */

const registeredEvents = {};

/**
 * Register events that can be listened to be other components/modules
 * @param {array | string} events - A list of event names. A single event may
 * also be passed as a string.
 * @returns {function} See triggerEvent
 */
const registerEvents = events => {
  const eventList = Array.isArray(events) ? events : [events];

  eventList.forEach(event => {
    if (!registeredEvents[event]) {
      registeredEvents[event] = new Set();
    }
  });
};

/**
 * Register a callback for a specific event
 * @param {String} event - The name of the event
 * @param {Function} callback
 */
const registerEventListener = (event, callback) => {
  const eventCallbacks = registeredEvents[event];
  if (!eventCallbacks) {
    logging.error(`${event} is not a registered event.`);
  } else {
    eventCallbacks.add(callback);
  }
};

/**
 * Trigger an event and fire all registered callbacks
 * @param {String} event - The name of the event
 * @param {*} data - Data to be passed to callback functions
 */
const triggerEvent = (event, data) => {
  const eventCallbacks = registeredEvents[event];
  if (!eventCallbacks) {
    registeredEvents(event);
    logging.log(`${event} has been registered as a new event.`);
  } else {
    eventCallbacks.forEach(callback => callback(data, event));
  }
};

/** Returns the current OpenTok session object */
// const getSession = () => session;
let getSession;

/** Returns the current OpenTok session credentials */
let getCredentials;

const createSessionEventListeners = session => {
  registerEvents(['streamCreated', 'streamDestroyed', 'error']);
  session.on({
    streamCreated(event) {
      streams[event.stream.id] = event.stream;
      triggerEvent('streamCreated', event.stream);
    },
    streamDestroyed(event) {
      delete streams[event.stream.id];
      triggerEvent('streamDestroyed', event.stream);
    },
  });
};

const initPackages = (session, options) => {
  const env = typeof module === 'object' && typeof module.exports === 'object' ?
    'node' :
    'browser';

  const availablePackages = {
    textChat: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-text-chat'),
      browser: () => TextChatAccPack, // eslint-disable-line no-undef
    },
    screenSharing: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-screen-sharing'),
      browser: () => ScreenSharingAccPack, // eslint-disable-line no-undef
    },
    annotation: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-annotation'),
      browser: () => AnnotationAccPack, // eslint-disable-line no-undef
    },
    archiving: { // eslint-disable-next-line global-require,import/no-extraneous-dependencies
      node: () => require('opentok-archiving'),
      browser: () => ArchivingAccPack, // eslint-disable-line no-undef
    },
  };
  const packages = {};
  options.packages.forEach((acceleratorPack) => {
    if (availablePackages[acceleratorPack]) { // eslint-disable-next-line no-param-reassign
      const packageName = `${acceleratorPack[0].toUpperCase()}${acceleratorPack.slice(1)}`;
      packages[packageName] = availablePackages[acceleratorPack][env]();
    } else {
      logging.log(`${acceleratorPack} is not a valid accelerator pack`);
    }
  });

  const packageOptions = packageName => {
    const accPack = { registerEvents, triggerEvent };
    const commOptions = packageName === 'communication' ?
      { publishers, subscribers, streams } : {};
    return Object.assign({}, options[packageName], commOptions, { session, accPack });
  };

  // eslint-disable-next-line global-require,import/no-extraneous-dependencies
  communication = require('./communication')(packageOptions('communication'));
  textChat = new packages.TextChat(packageOptions('textChat'));
  screenSharing = new packages.ScreenSharing(packageOptions('screenSharing'));
  annotation = new packages.Annotation(packageOptions('annotation'));
  archiving = new packages.Archiving(packageOptions('archiving'));
};

/**
 * Ensures that we have the required credentials
 * @param {Object} credentials
 * @param {String} credentials.apiKey
 * @param {String} credentials.sessionId
 * @param {String} credentials.token
 */
const validateCredentials = credentials => {
  const required = ['apiKey', 'sessionId', 'token'];
  required.forEach(credential => {
    if (!credentials[credential]) {
      logging.error(`${credential} is a required credential`);
    }
  });
};

/**
 * Connect to the session
 */
const connect = () => {
  const session = getSession();
  const { token } = getCredentials();
  session.connect(token);
};

/**
 * Initialize the accelerator pack
 * @param {Object} options
 * @param {Object} options.credentials
 */
const init = (options) => {
  if (!options) {
    logging.error('Missing options required for initialization');
  }
  const { credentials } = options;
  validateCredentials(credentials);
  const session = OT.initSession(credentials.apiKey, credentials.sessionId, error => {
    if (error) {
      logging.error(error);
    } else {
      initPackages(session, options);
      createSessionEventListeners(session);
      getSession = () => session;
      getCredentials = () => credentials;
    }
  });
};

module.exports = {
  init,
  connect,
  getSession,
  registeredEvents,
  registerEventListener,
  triggerEvent,
};
<|endoftext|>