<commit_before>(function() {
  'use strict';

  function Vector() {
    var self = this;
    self.values = [];
    self.length = 0;

    var argument,
        i;
    for(i = 0; i < arguments.length; i++) {
      argument = arguments[i];

      if(argument instanceof Vector)
        self.combine(argument);
      else if(typeof argument === 'object')
        self.combine(Vector.construct(argument));
      else
        self.push(argument);
    }

    return self;
  }

  // array of arguments to function arguments (e.g. f.construct([a, b, c]) => f(a, b, c))
  Function.prototype.construct = function(args) {
    var object = Object.create(this.prototype);
    this.apply(object, args);
    return object;
  };

  Vector.prototype.add = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match!');

    var result = new Vector(),
        a = this.values,
        b = vector.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(a[i] + b[i]);

    return result;
  };

  Vector.prototype.subtract = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match');

    var result = new Vector(),
        a = this.values,
        b = vector.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(a[i] - b[i]);

    return result;
  };

  Vector.prototype.scale = function(scalar) {
    var result = new Vector(),
        values = this.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(values[i] * scalar);

    return result;
  };

  Vector.prototype.normalize = function() {
    var result = new Vector(this);
    return result.scale(1 / result.magnitude());
  };

  Vector.prototype.project = function(vector) {
    return vector.scale(this.dot(vector) / vector.dot(vector));
  };

  Vector.prototype.zeros = function(count) {
    if(count < 0)
      throw new Error('invalid size');

    var zeros = [],
        i;
    for(i = 0; i < count; i++)
      zeros.push(0);

    return Vector.construct(zeros);
  };

  Vector.prototype.ones = function(count) {
    if(count < 0)
      throw new Error('invalid size');

    var ones = [],
        i;
    for(i = 0; i < count; i++)
      ones.push(1);

    return Vector.construct(ones);
  };

  Vector.range = function() {
    var args = [].slice.call(arguments, 0),
        backwards = false,
        start, step, end;

    switch(args.length) {
      case 2:
        end = args.pop();
        step = 1;
        start = args.pop();
        break;
      case 3:
        end = args.pop();
        step = args.pop();
        start = args.pop();
        break;
      default:
        throw new Error('invalid range');
    }

    if(end - start < 0) {
      var copy = end;
      end = start;
      start = copy;
      backwards = true;
    }

    if(step > end - start)
      throw new Error('invalid range');

    var vector = new Vector(),
        i;
    for(i = start; i < end; i += step)
      vector.push(backwards ? end - i + start : i);

    return vector;
  };

  Vector.prototype.dot = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match');

    var result = 0,
        a = this.values,
        b = vector.values,
        i, l;

    for(i = 0, l = this.length; i < l; i++)
      result += a[i] * b[i];

    return result;
  };

  Vector.prototype.magnitude = function() {
    var result = 0,
        values = this.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result += values[i] * values[i];

    return Math.sqrt(result);
  };

  Vector.prototype.angle = function(vector) {
    return Math.acos(this.dot(vector) / this.magnitude() * vector.magnitude());
  };

  Vector.prototype.equals = function(vector) {
    if(this.length !== vector.length)
      return false;

    var a = this.values,
        b = vector.values,
        i = 0, l = this.length;

    while(i < l && a[i] === b[i++]) {};

    return i === l;
  };

  Vector.prototype.get = function(index) {
    if(index < 0 || index > this.length - 1)
      throw new Error('index out of bounds');

    return this.values[index];
  };

  Vector.prototype.min = function() {
    var min = Number.POSITIVE_INFINITY,
        values = this.values,
        value,
        i, l;

    for(i = 0, l = values.length; i < l; i++) {
      value = values[i];
      if(value < min)
        min = value;
    }

    return min;
  };

  Vector.prototype.max = function() {
    var max = Number.NEGATIVE_INFINITY,
        values = this.values,
        value,
        i, l;

    for(i = 0, l = this.length; i < l; i++) {
      value = values[i];
      if(value > max)
        max = value;
    }

    return max;
  };

  Vector.prototype.set = function(index, value) {
    if(index < 0 || index > this.length - 1)
      throw new Error('index out of bounds');

    this.values[index] = value;
    return this;
  };

  Vector.prototype.combine = function(vector) {
    var values = vector.values,
        i, l;
    for(i = 0, l = vector.length; i < l; i++)
      this.push(values[i]);

    return this;
  };

  Vector.prototype.push = function(value) {
    this.values.push(value);
    this.length++;

    return this;
  };

  Vector.prototype.map = function(callback) {
    var vector = new Vector(this),
        i;
    for(i = 0; i < this.length; i++)
      vector.values[i] = callback(vector.values[i]);

    return vector;
  };

  Vector.prototype.each = function(callback) {
    var i;
    for(i = 0; i < this.length; i++)
      callback(this.values[i], i);

    return this;
  };

  Vector.prototype.toString = function() {
    return '[' + this.values.join(', ') + ']';
  };

  Vector.prototype.toArray = function() {
    return this.values;
  };

  module.exports = Vector;
})();<commit_msg>Update vector.js<commit_after>(function() {
  'use strict';

  function Vector() {
    var self = this;
    self.values = [];
    self.length = 0;

    var argument,
        i;
    for(i = 0; i < arguments.length; i++) {
      argument = arguments[i];

      if(argument instanceof Vector)
        self.combine(argument);
      else if(typeof argument === 'object')
        self.combine(Vector.construct(argument));
      else
        self.push(argument);
    }

    return self;
  }

  // array of arguments to function arguments (e.g. f.construct([a, b, c]) => f(a, b, c))
  Function.prototype.construct = function(args) {
    var object = Object.create(this.prototype);
    this.apply(object, args);
    return object;
  };

  Vector.prototype.add = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match!');

    var result = new Vector(),
        a = this.values,
        b = vector.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(a[i] + b[i]);

    return result;
  };

  Vector.prototype.subtract = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match');

    var result = new Vector(),
        a = this.values,
        b = vector.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(a[i] - b[i]);

    return result;
  };

  Vector.prototype.scale = function(scalar) {
    var result = new Vector(),
        values = this.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result.push(values[i] * scalar);

    return result;
  };

  Vector.prototype.normalize = function() {
    var result = new Vector(this);
    return result.scale(1 / result.magnitude());
  };

  Vector.prototype.project = function(vector) {
    return vector.scale(this.dot(vector) / vector.dot(vector));
  };

  Vector.zeros = function(count) {
    if(count < 0)
      throw new Error('invalid size');

    var zeros = [],
        i;
    for(i = 0; i < count; i++)
      zeros.push(0);

    return Vector.construct(zeros);
  };

  Vector.ones = function(count) {
    if(count < 0)
      throw new Error('invalid size');

    var ones = [],
        i;
    for(i = 0; i < count; i++)
      ones.push(1);

    return Vector.construct(ones);
  };

  Vector.range = function() {
    var args = [].slice.call(arguments, 0),
        backwards = false,
        start, step, end;

    switch(args.length) {
      case 2:
        end = args.pop();
        step = 1;
        start = args.pop();
        break;
      case 3:
        end = args.pop();
        step = args.pop();
        start = args.pop();
        break;
      default:
        throw new Error('invalid range');
    }

    if(end - start < 0) {
      var copy = end;
      end = start;
      start = copy;
      backwards = true;
    }

    if(step > end - start)
      throw new Error('invalid range');

    var vector = new Vector(),
        i;
    for(i = start; i < end; i += step)
      vector.push(backwards ? end - i + start : i);

    return vector;
  };

  Vector.prototype.dot = function(vector) {
    if(this.length !== vector.length)
      throw new Error('sizes do not match');

    var result = 0,
        a = this.values,
        b = vector.values,
        i, l;

    for(i = 0, l = this.length; i < l; i++)
      result += a[i] * b[i];

    return result;
  };

  Vector.prototype.magnitude = function() {
    var result = 0,
        values = this.values,
        i, l;
    for(i = 0, l = this.length; i < l; i++)
      result += values[i] * values[i];

    return Math.sqrt(result);
  };

  Vector.prototype.angle = function(vector) {
    return Math.acos(this.dot(vector) / this.magnitude() * vector.magnitude());
  };

  Vector.prototype.equals = function(vector) {
    if(this.length !== vector.length)
      return false;

    var a = this.values,
        b = vector.values,
        i = 0, l = this.length;

    while(i < l && a[i] === b[i++]) {};

    return i === l;
  };

  Vector.prototype.get = function(index) {
    if(index < 0 || index > this.length - 1)
      throw new Error('index out of bounds');

    return this.values[index];
  };

  Vector.prototype.min = function() {
    var min = Number.POSITIVE_INFINITY,
        values = this.values,
        value,
        i, l;

    for(i = 0, l = values.length; i < l; i++) {
      value = values[i];
      if(value < min)
        min = value;
    }

    return min;
  };

  Vector.prototype.max = function() {
    var max = Number.NEGATIVE_INFINITY,
        values = this.values,
        value,
        i, l;

    for(i = 0, l = this.length; i < l; i++) {
      value = values[i];
      if(value > max)
        max = value;
    }

    return max;
  };

  Vector.prototype.set = function(index, value) {
    if(index < 0 || index > this.length - 1)
      throw new Error('index out of bounds');

    this.values[index] = value;
    return this;
  };

  Vector.prototype.combine = function(vector) {
    var values = vector.values,
        i, l;
    for(i = 0, l = vector.length; i < l; i++)
      this.push(values[i]);

    return this;
  };

  Vector.prototype.push = function(value) {
    this.values.push(value);
    this.length++;

    return this;
  };

  Vector.prototype.map = function(callback) {
    var vector = new Vector(this),
        i;
    for(i = 0; i < this.length; i++)
      vector.values[i] = callback(vector.values[i]);

    return vector;
  };

  Vector.prototype.each = function(callback) {
    var i;
    for(i = 0; i < this.length; i++)
      callback(this.values[i], i);

    return this;
  };

  Vector.prototype.toString = function() {
    return '[' + this.values.join(', ') + ']';
  };

  Vector.prototype.toArray = function() {
    return this.values;
  };

  module.exports = Vector;
})();
<|endoftext|>


<commit_before>module.exports = {
  '0x0043': ['uno'],
  '0x0036': ['imuduino', 'leonardo', 'little-bits'],
  '0x0037': ['imuduino', 'micro'],
  '0x0042': ['mega'],
  '0x2404': ['blend-micro'],
  '0x516d': ['qduino'],
  '0x6001': ['sf-mega-pro', 'nano', 'duemilanove168'],
  '0x6015': ['tinyduino'],
  '0x6051': ['pinoccio'],
  '0x8036': ['imuduino', 'leonardo', 'little-bits'],
  '0x8037': ['imuduino', 'micro'],
  '0x9206': ['sf-pro-micro']
};
<commit_msg>Consolidated sf-mega-pro with mega for compatibility with avrgirl<commit_after>module.exports = {
  '0x0043': ['uno'],
  '0x0036': ['imuduino', 'leonardo', 'little-bits'],
  '0x0037': ['imuduino', 'micro'],
  '0x0042': ['mega'],
  '0x2404': ['blend-micro'],
  '0x516d': ['qduino'],
  '0x6001': ['mega', 'nano', 'duemilanove168'],
  '0x6015': ['tinyduino'],
  '0x6051': ['pinoccio'],
  '0x8036': ['imuduino', 'leonardo', 'little-bits'],
  '0x8037': ['imuduino', 'micro'],
  '0x9206': ['sf-pro-micro']
};
<|endoftext|>


<commit_before>/*global require, module*/
'use strict';

var $          = require('cheerio'),
    definition = require('./definition'),
    req        = require('../utils/req'),
    URI        = require('URIjs');

/**
 * Parses the WWW-Authenticate header of the Service Provider response.
 *
 * @param {string} challenge is the value of the WWW-Authenticate header.
 * @returns An object containing the Authorization Provider URI and the
 * available modes.
 *
 * @private
 */

var parseWwwAuthenticate = function(challenge) {
  var regex = /(?:(\w*)\=\"(.*?))*\"/g;
  var match = [], data = {};
  while ((match = regex.exec(challenge)) !== null) {
    data[match[1]] = match[2];
  }

  var modesArray = data.modes.split(',');
  var modes = {
    client:  (modesArray.indexOf('client') !== -1),
    user:    (modesArray.indexOf('user') !== -1),
    anonymous: false
  };

  return {
    apBaseUrl: data.uri+'/',
    modes: modes
  };
};

/**
 * Extracts the tags from the XML document.
 *
 * @param xmlData the source document.
 * @returns an array of tags containing the following fields:
 * author, title, summary, publishedDate.
 *
 * @private
 */

var extractTags = function(xmlData) {
  var tags = [];
  var doc = $(xmlData);
  var author = doc.find('author name').first().text();
  var entries = doc.find('entry');

  for (var i = 0; i < entries.length; i++) {
    var tag = {
      author: author,
      title: $(entries[i]).find('title').first().text(),
      summary: $(entries[i]).find('summary').first().text(),
      publishedDate: $(entries[i]).find('published').first().text()
    };

    tags.push(tag);
  }

  return tags;
};

var uriWithPath = function(baseUrl, path) {
  return URI(baseUrl).path(path).toString();
};

var getTagUrl = function(baseUrl) {
  return uriWithPath(baseUrl, definition.endpoints.tag);
};

var getTagsUrl = function(baseUrl) {
  return uriWithPath(baseUrl, definition.endpoints.getTags);
};

/** @namespace */

var RadioTAG = {

  /**
   * Posts a tag to the RadioTAG service.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param {string} bearer Bearer URI for the radio station being tagged.
   * @param {string} timeSource The system clock's source of time
   *   (either 'broadcast', 'user' or 'ntp').
   * @param {Date} time The time of the tag.
   * @param {string} accessToken The CPA access token which authenticates
   *   the request.
   * @param done
   */

  tag: function(baseUrl, bearer, timeSource, time, accessToken, done) {
    var data = {
      bearer: bearer,
      time:   Math.floor(time.getTime() / 1000)
    };

    if (timeSource) {
      // jshint -W106
      data.time_source = timeSource;
      // jshint +W106
    }

    var tagUrl = getTagUrl(baseUrl);

    req.postForm(tagUrl, data, accessToken)
      .then(
        function(response) {
          var tag = extractTags(response.body)[0];

          done(null, tag);
        },
        function(response) {
          done(response);
        }
      );
  },

  /**
   * Retrieves the list of tags for the device or the user represented by the
   * access token.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param {string} accessToken The CPA access token which authenticates
   *   the request.
   * @param done
   */

  getTags: function(baseUrl, accessToken, done) {
    var tagsUrl = getTagsUrl(baseUrl);

    req.get(tagsUrl, accessToken)
      .then(
        function(response) {
          var tags = extractTags(response.body);
          done(null, tags);
        },
        function(response) {
          done(response);
        }
      );
  },

  /**
   * Discovers the CPA Auth Provider associated with the RadioTAG service, and
   * the available authentication modes.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param done
   */

  getAuthProvider: function(baseUrl, done) {
    var callback = function(response) {
      var challenge = response.headers['www-authenticate'];

      if (!challenge) {
        done(new Error(definition.errorMessages.headerNotFound));
        return;
      }

      var authProvider = parseWwwAuthenticate(challenge);
      done(null, authProvider.apBaseUrl, authProvider.modes);
    };

    var tagUrl = getTagUrl(baseUrl);

    return req.postForm(tagUrl)
      .then(callback, callback);
  }
};

module.exports = RadioTAG;
<commit_msg>Added JSDoc comments<commit_after>/*global require, module*/
'use strict';

var $          = require('cheerio'),
    definition = require('./definition'),
    req        = require('../utils/req'),
    URI        = require('URIjs');

/**
 * Parses the WWW-Authenticate header of the Service Provider response.
 *
 * @param {string} challenge is the value of the WWW-Authenticate header.
 * @returns An object containing the Authorization Provider URI and the
 * available modes.
 *
 * @private
 */

var parseWwwAuthenticate = function(challenge) {
  var regex = /(?:(\w*)\=\"(.*?))*\"/g;
  var match = [], data = {};
  while ((match = regex.exec(challenge)) !== null) {
    data[match[1]] = match[2];
  }

  var modesArray = data.modes.split(',');
  var modes = {
    client:  (modesArray.indexOf('client') !== -1),
    user:    (modesArray.indexOf('user') !== -1),
    anonymous: false
  };

  return {
    apBaseUrl: data.uri+'/',
    modes: modes
  };
};

/**
 * Extracts the tags from the XML document.
 *
 * @param xmlData the source document.
 * @returns an array of tags containing the following fields:
 * author, title, summary, publishedDate.
 *
 * @private
 */

var extractTags = function(xmlData) {
  var tags = [];
  var doc = $(xmlData);
  var author = doc.find('author name').first().text();
  var entries = doc.find('entry');

  for (var i = 0; i < entries.length; i++) {
    var tag = {
      author: author,
      title: $(entries[i]).find('title').first().text(),
      summary: $(entries[i]).find('summary').first().text(),
      publishedDate: $(entries[i]).find('published').first().text()
    };

    tags.push(tag);
  }

  return tags;
};

var uriWithPath = function(baseUrl, path) {
  return URI(baseUrl).path(path).toString();
};

var getTagUrl = function(baseUrl) {
  return uriWithPath(baseUrl, definition.endpoints.tag);
};

var getTagsUrl = function(baseUrl) {
  return uriWithPath(baseUrl, definition.endpoints.getTags);
};

/** @namespace */

var RadioTAG = {

  /**
   * Callback function for the {@link RadioTAG.tag} function.
   *
   * @callback tagCallback
   * @param {Error|null} error On success, this value is null;
   *   on error, it is an Error object containing an error message.
   * @param {Object|null} data On success, this value is an object containing
   *   the information described below; on error, this value is
   *   null
   * @param {string} data.author The name of the service provider.
   * @param {string} data.title A title associated with the tag, such as the
   *   name of the radio programme.
   * @param {string} data.summary A brief description associated with the tag,
   *   such as artist and song title, or more information about the radio
   *   programme.
   * @param {string} data.publishedDate The time of the tag.
   */

  /**
   * Posts a tag to the RadioTAG service.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param {string} bearer Bearer URI for the radio station being tagged.
   * @param {string} timeSource The system clock's source of time
   *   (either 'broadcast', 'user' or 'ntp').
   * @param {Date} time The time of the tag.
   * @param {string} accessToken The CPA access token which authenticates
   *   the request.
   * @param {tagCallback} done Callback function.
   */

  tag: function(baseUrl, bearer, timeSource, time, accessToken, done) {
    var data = {
      bearer: bearer,
      time:   Math.floor(time.getTime() / 1000)
    };

    if (timeSource) {
      // jshint -W106
      data.time_source = timeSource;
      // jshint +W106
    }

    var tagUrl = getTagUrl(baseUrl);

    req.postForm(tagUrl, data, accessToken)
      .then(
        function(response) {
          var tag = extractTags(response.body)[0];

          done(null, tag);
        },
        function(response) {
          done(response);
        }
      );
  },

  /**
   * Callback function for the {@link RadioTAG.getTags} function.
   *
   * @callback getTagsCallback
   * @param {Error|null} error On success, this value is null;
   *   on error, it is an Error object containing an error message.
   * @param {Object|null} data On success, this value is an array of objects,
   *   each containing the information described below; on error, this value is
   *   null
   * @param {string} data.author The name of the service provider.
   * @param {string} data.title A title associated with the tag, such as the
   *   name of the radio programme.
   * @param {string} data.summary A brief description associated with the tag,
   *   such as artist and song title, or more information about the radio
   *   programme.
   * @param {string} data.publishedDate The time of the tag.
   */

  /**
   * Retrieves the list of tags for the device or the user represented by the
   * access token.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param {string} accessToken The CPA access token which authenticates
   *   the request.
   * @param {getTagsCallback} done Callback function.
   */

  getTags: function(baseUrl, accessToken, done) {
    var tagsUrl = getTagsUrl(baseUrl);

    req.get(tagsUrl, accessToken)
      .then(
        function(response) {
          var tags = extractTags(response.body);
          done(null, tags);
        },
        function(response) {
          done(response);
        }
      );
  },

  /**
   * Callback function for the {@link RadioTAG.getAuthProvider}
   * function.
   *
   * @callback getAuthProviderCallback
   * @param {Error|null} error On success, this value is null;
   *   on error, it is an Error object containing an error message.
   * @param {string|null} baseUrl On success, this value the base URL of the
   *   authorization provider associated with this service provider.
   * @param {array|null} modes On success, this value is an array of strings
   *   indicating which authentication modes are available, either "client",
   *   "user", or both.
   */

  /**
   * Discovers the CPA Auth Provider associated with the RadioTAG service, and
   * the available authentication modes.
   *
   * @param {string|URI} baseUrl The base URL of the RadioTAG service.
   * @param {getAuthProviderCallback} done Callback function.
   */

  getAuthProvider: function(baseUrl, done) {
    var callback = function(response) {
      var challenge = response.headers['www-authenticate'];

      if (!challenge) {
        done(new Error(definition.errorMessages.headerNotFound));
        return;
      }

      var authProvider = parseWwwAuthenticate(challenge);
      done(null, authProvider.apBaseUrl, authProvider.modes);
    };

    var tagUrl = getTagUrl(baseUrl);

    return req.postForm(tagUrl)
      .then(callback, callback);
  }
};

module.exports = RadioTAG;
<|endoftext|>


<commit_before>var boards = [
  {
    name: 'uno',
    baud: 115200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x0043', '0x7523', '0x0001', '0xea60'],
    protocol: 'stk500v1'
  },
  {
    name: 'micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0037', '0x8037', '0x0036', '0x0237'],
    protocol: 'avr109'
  },
  {
    name: 'imuduino',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8037', '0x8036'],
    protocol: 'avr109'
  },
  {
    name: 'leonardo',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036', '0x800c'],
    protocol: 'avr109'
  },
  {
    name: 'arduboy',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036', '0x800c'],
    protocol: 'avr109'
  },
  {
    name: 'feather',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x800c', '0x000c'],
    protocol: 'avr109'
  },
  {
    name: 'little-bits',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036'],
    protocol: 'avr109'
  },
  {
    name: 'blend-micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x2404'],
    protocol: 'avr109'
  },
  {
    name: 'nano',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001', '0x7523'],
    protocol: 'stk500v1'
  },
  {
    name: 'duemilanove168',
    baud: 19200,
    signature: new Buffer([0x1e, 0x94, 0x06]),
    pageSize: 128,
    numPages: 128,
    timeout: 400,
    productId: ['0x6001'],
    protocol: 'stk500v1'
  },
  {
    name: 'duemilanove328',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x14]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001'],
    protocol: 'stk500v1'
  },
  // the alias is here because of an accidental naming change of the tinyduino
  // keeping in for backwards compatibility (SHA 05d65842)
  {
    name: 'tinyduino',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6015'],
    protocol: 'stk500v1',
    aliases: ['tinduino']
  },
  {
    name: 'bqZum',
    baud: 19200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001', '0x7523'],
    protocol: 'stk500v1'
  },
  {
    name: 'mega',
    baud: 115200,
    signature: new Buffer([0x1e, 0x98, 0x01]), // ATmega2560
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x0042', '0x6001', '0x0010', '0x7523'],
    protocol: 'stk500v2'
  },
  {
    name: 'adk',
    baud: 115200,
    signature: new Buffer([0x1e, 0x98, 0x01]), // ATmega2560
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x0044', '0x6001', '0x003F'],
    protocol: 'stk500v2'
  },
  {
    name: 'sf-pro-micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x9206', '0x9205'],
    protocol: 'avr109'
  },
  {
    name: 'pro-mini',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    protocol: 'stk500v1'
  },
  {
    name: 'qduino',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x516d', '0x514d'],
    protocol: 'avr109'
  },
  {
    name: 'pinoccio',
    baud: 115200,
    signature: new Buffer([0x1e, 0xa8, 0x02]), // ATmega256RFR2
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x6051'],
    protocol: 'stk500v2'
  },
  {
    name: 'lilypad-usb',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x9207', '0x9208', '0x1B4F'],
    protocol: 'avr109'
  },
  {
    name: 'yun',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0041', '0x8041'],
    protocol: 'avr109'
  },
  {
    name: 'esplora',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x003C', '0x803C'],
    protocol: 'avr109'
  },
  {
    name: 'circuit-playground-classic',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0011', '0x8011'],
    protocol: 'avr109'
  }
];

/**
 * Generate an object with board name keys for faster lookup
 * @return {object} byBoardName
 */
function boardLookupTable() {
  var byBoard = {};
  for (var i = 0; i < boards.length; i++) {
    var currentBoard = boards[i];
    byBoard[currentBoard.name] = currentBoard;

    var aliases = currentBoard.aliases;
    if (Array.isArray(aliases)) {
      for (var j = 0; j < aliases.length; j++) {
        var currentAlias = aliases[j];
        byBoard[currentAlias] = currentBoard;
      }
    }
  }
  return byBoard;
}

module.exports = boardLookupTable();
<commit_msg>Added BQ boards ZUM Junior and ZUM Core 2<commit_after>var boards = [
  {
    name: 'uno',
    baud: 115200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x0043', '0x7523', '0x0001', '0xea60'],
    protocol: 'stk500v1'
  },
  {
    name: 'micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0037', '0x8037', '0x0036', '0x0237'],
    protocol: 'avr109'
  },
  {
    name: 'imuduino',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8037', '0x8036'],
    protocol: 'avr109'
  },
  {
    name: 'leonardo',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036', '0x800c'],
    protocol: 'avr109'
  },
  {
    name: 'arduboy',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036', '0x800c'],
    protocol: 'avr109'
  },
  {
    name: 'feather',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x800c', '0x000c'],
    protocol: 'avr109'
  },
  {
    name: 'little-bits',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0036', '0x8036'],
    protocol: 'avr109'
  },
  {
    name: 'blend-micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x2404'],
    protocol: 'avr109'
  },
  {
    name: 'nano',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001', '0x7523'],
    protocol: 'stk500v1'
  },
  {
    name: 'duemilanove168',
    baud: 19200,
    signature: new Buffer([0x1e, 0x94, 0x06]),
    pageSize: 128,
    numPages: 128,
    timeout: 400,
    productId: ['0x6001'],
    protocol: 'stk500v1'
  },
  {
    name: 'duemilanove328',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x14]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001'],
    protocol: 'stk500v1'
  },
  // the alias is here because of an accidental naming change of the tinyduino
  // keeping in for backwards compatibility (SHA 05d65842)
  {
    name: 'tinyduino',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6015'],
    protocol: 'stk500v1',
    aliases: ['tinduino']
  },
  {
    name: 'mega',
    baud: 115200,
    signature: new Buffer([0x1e, 0x98, 0x01]), // ATmega2560
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x0042', '0x6001', '0x0010', '0x7523'],
    protocol: 'stk500v2'
  },
  {
    name: 'adk',
    baud: 115200,
    signature: new Buffer([0x1e, 0x98, 0x01]), // ATmega2560
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x0044', '0x6001', '0x003F'],
    protocol: 'stk500v2'
  },
  {
    name: 'sf-pro-micro',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x9206', '0x9205'],
    protocol: 'avr109'
  },
  {
    name: 'pro-mini',
    baud: 57600,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    protocol: 'stk500v1'
  },
  {
    name: 'qduino',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x516d', '0x514d'],
    protocol: 'avr109'
  },
  {
    name: 'pinoccio',
    baud: 115200,
    signature: new Buffer([0x1e, 0xa8, 0x02]), // ATmega256RFR2
    pageSize: 256,
    delay1: 10,
    delay2: 1,
    timeout:0xc8,
    stabDelay:0x64,
    cmdexeDelay:0x19,
    synchLoops:0x20,
    byteDelay:0x00,
    pollValue:0x53,
    pollIndex:0x03,
    productId: ['0x6051'],
    protocol: 'stk500v2'
  },
  {
    name: 'lilypad-usb',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x9207', '0x9208', '0x1B4F'],
    protocol: 'avr109'
  },
  {
    name: 'yun',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0041', '0x8041'],
    protocol: 'avr109'
  },
  {
    name: 'esplora',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x003C', '0x803C'],
    protocol: 'avr109'
  },
  {
    name: 'circuit-playground-classic',
    baud: 57600,
    signature: new Buffer([0x43, 0x41, 0x54, 0x45, 0x52, 0x49, 0x4e]),
    productId: ['0x0011', '0x8011'],
    protocol: 'avr109'
  },
  /** BQ - Arduino Based Boards. Used in Bitbloq -> bitbloq.bq.com and Arduino IDE*/
  {
    name: 'zumjunior',
    baud: 115200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0xEA60'],
    protocol: 'stk500v1'
  },
  {
    name: 'zumcore2',
    baud: 115200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0xEA60'],
    protocol: 'stk500v1'
  },
  {
    name: 'bqZum',
    baud: 19200,
    signature: new Buffer([0x1e, 0x95, 0x0f]),
    pageSize: 128,
    numPages: 256,
    timeout: 400,
    productId: ['0x6001', '0x7523'],
    protocol: 'stk500v1'
  }
  /** END OF BQ - Arduino Based Boards. Used in Bitbloq -> bitbloq.bq.com and Arduino IDE*/
];

/**
 * Generate an object with board name keys for faster lookup
 * @return {object} byBoardName
 */
function boardLookupTable() {
  var byBoard = {};
  for (var i = 0; i < boards.length; i++) {
    var currentBoard = boards[i];
    byBoard[currentBoard.name] = currentBoard;

    var aliases = currentBoard.aliases;
    if (Array.isArray(aliases)) {
      for (var j = 0; j < aliases.length; j++) {
        var currentAlias = aliases[j];
        byBoard[currentAlias] = currentBoard;
      }
    }
  }
  return byBoard;
}

module.exports = boardLookupTable();
<|endoftext|>


<commit_before>/***********************
 **     viewer.js     **
 **  NODE.JS SERVER   **
 ***********************/

// for express and socket
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var url = require("url");
var path = require("path");

// server host and port
var PORT = 1337; //40143?
//var HOST = '127.0.0.1';
//var HOST = '192.168.1.138'
var HOST = '10.26.67.68';

// for referencing files
app.use('/css', express.static('css'));
app.use('/images', express.static('images'));
app.use('/js', express.static('js'));
app.use('/videos', express.static('videos'));
app.use('/Volumes/AMAZON', express.static('Volumes/AMAZON')); // (Doesn't work)

// websocket
io.on('connection', function(socket){
    socket.on('loadMessages', function(){
        io.emit('setMessage', "Socket.io test successful.");
    });

    socket.on('print', function(){
        console.log(vidStreamer);
    })

});

// load webpage
app.get('/', function(req, res){
    console.log("viewer.html loaded");
    res.sendFile(__dirname + '/viewer.html', {maxAge: 0});
});

// creating server
http.listen(PORT, HOST, function(){
    console.log('Socket listening on ' + HOST + ':' + PORT);
});

<commit_msg>Removed a line<commit_after>/***********************
 **     viewer.js     **
 **  NODE.JS SERVER   **
 ***********************/

// for express and socket
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var url = require("url");
var path = require("path");

// server host and port
var PORT = 1337; //40143?
//var HOST = '127.0.0.1';
var HOST = '10.26.67.68';

// for referencing files
app.use('/css', express.static('css'));
app.use('/images', express.static('images'));
app.use('/js', express.static('js'));
app.use('/videos', express.static('videos'));
app.use('/Volumes/AMAZON', express.static('Volumes/AMAZON')); // (Doesn't work)

// websocket
io.on('connection', function(socket){
    socket.on('loadMessages', function(){
        io.emit('setMessage', "Socket.io test successful.");
    });

    socket.on('print', function(){
        console.log(vidStreamer);
    })

});

// load webpage
app.get('/', function(req, res){
    console.log("viewer.html loaded");
    res.sendFile(__dirname + '/viewer.html', {maxAge: 0});
});

// creating server
http.listen(PORT, HOST, function(){
    console.log('Socket listening on ' + HOST + ':' + PORT);
});

<|endoftext|>


<commit_before>/**
 * Created by khejing on 2015/6/30.
 */

var mqtt = require('mqtt');
var headless = require('headless');
var electronPath = require('electron-prebuilt');
var childProcess = require('child_process');
var portFinder = require('portfinder');
var ffmpeg = require('fluent-ffmpeg');
var moment = require('moment');
var m3u8 = require("m3u8");
var fs = require("fs");
var PouchDB = require('pouchdb');

var recordingTopic = "recording";
var mqttClientInstance = mqtt.connect("mqtt://localhost:1883", {clientId: recordingTopic});
mqttClientInstance.on('connect', function () {
    console.log("connect mqtt server success");
});
mqttClientInstance.on('error',function(error) {
    console.log("mqtt connect failed: ", error);
});
mqttClientInstance.subscribe(recordingTopic);

mqttClientInstance.on('message', function(messageTopic, data) {
    var msg = JSON.parse(data);
    var options = {
        display: {width: 1366, height: 768, depth: 24}
    };
    headless(options, function(err, xvfbChildProcess, servernum) {
        // childProcess is a ChildProcess, as returned from child_process.spawn()
        console.log('Xvfb running on server number', servernum);
        console.log('Xvfb pid', xvfbChildProcess.pid);
        console.log('err should be null', err);
        var displayOpt = ":"+servernum+".0";

        // spawn electron after xvfb has been started
        var electronChild = childProcess.spawn(electronPath, [__dirname+"/electron_app"], {env: {DISPLAY: displayOpt, TopicToSubscribe: data}});
        electronChild.stderr.on('data', function(data){
            process.stdout.write(data.toString());
        });

        portFinder.getPort(function (err, port) {
            console.log("got free port: "+port);
            function ffmpegLog(data){
                console.log(data);
            }
            function ffmpegOutput(command){
                command
                    .audioCodec("aac")
                    .videoCodec("libx264")
                    .outputOptions(["-pix_fmt yuv420p", "-crf 28", "-hls_time 10", "-hls_list_size 0","-threads 0", "-shortest"]);
            }
            var recordingFileName = msg.teacherTopic+"-"+msg.type+"-"+moment().format("YYYYMMDDHHmmss");
            var dirName = null;
            if(msg.type === "tutor-video" || msg.type === "answer-video"){
                dirName = "video-recording";
            }
            var recordingFilePath = "/var/lib/"+dirName+"/"+recordingFileName;
            var ffmpegCommand = ffmpeg({logger: {debug: ffmpegLog, info: ffmpegLog, warn: ffmpegLog, error: ffmpegLog}});
            ffmpegCommand
                .input("tcp://localhost:"+port+"?listen=1")
                .input(displayOpt)
                .inputFormat("x11grab")
                .inputOptions(["-itsoffset 5", "-framerate 25", "-video_size 1366x768", "-draw_mouse 0"])
                .output(recordingFilePath+"-desktop"+".m3u8")
                .size("1280x720")
                .preset(ffmpegOutput)
                .output(recordingFilePath+"-tablet"+".m3u8")
                .size("640x360")
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 1000K", "-bufsize 2000K"])
                .output(recordingFilePath+"-smartphone"+".m3u8")
                .size("480x320")
                .autopad()
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 500K", "-bufsize 1000K"])
                .on("error", function(err, stdout, stderr){
                    console.log("got error from ffmpeg: "+err.message);
                    console.log("ffmpeg stderr: "+stderr);
                })
                .on("start", function(command){
					console.log(command);
					mqttClientInstance.publish(msg.clientId, JSON.stringify({recording: "Port", port: port}));
				})
                .on("end", function(){
                    console.log("ffmpeg ended!!!");
                    electronChild.kill();
                    xvfbChildProcess.kill();
                    var m3u8Content = m3u8.M3U.create();
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-desktop"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 2001000,
                        RESOLUTION: "1280x720"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-tablet"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 1001000,
                        RESOLUTION: "640x360"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-smartphone"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 510000,
                        RESOLUTION: "480x320"
                    });
                    fs.writeFile(recordingFilePath+".m3u8", m3u8Content.toString(), null, function(err){
                        if(err === null){
                            ffmpeg.ffprobe(recordingFilePath+".m3u8", function(err, metadata){
                                var db = new PouchDB("http://localhost:5984/"+
                                    msg.teacherTopic.slice(0, msg.teacherTopic.lastIndexOf("-", msg.teacherTopic.length - 1))+
                                    "%2F"+
                                    msg.studentTopics[0].slice(0, msg.studentTopics[0].lastIndexOf("-", msg.studentTopics[0].length - 1)));
                                db.get(msg.docId, null, function(err, result){
                                    result.duration = metadata.format.duration;
                                    result.recordingFileName = recordingFileName;
                                    result.syncStatus = [false, false];
                                    db.put(result, function(){
                                        //TODO: if teacher or student is offline, then don't need to send msg
                                        var replyMsg = {
                                            chat: "NewMessage",
                                            docId: msg.docId,
                                            clientId: msg.studentTopics[0]
                                        };
                                        mqttClientInstance.publish(msg.teacherTopic, JSON.stringify(replyMsg));
                                        replyMsg.clientId = msg.teacherTopic;
                                        mqttClientInstance.publish(msg.studentTopics[0], JSON.stringify(replyMsg));
                                    });
                                });
                            });
                        }
                    });
                })
                .run();
        });
    });
});
/* when got exit signal, then exit
mqttClientInstance.end();
mqttClientInstance = null;
console.log("mqtt client has been destroyed");
*/<commit_msg>zerolantency还是必须得加的，否则视频变短这事就不能接受<commit_after>/**
 * Created by khejing on 2015/6/30.
 */

var mqtt = require('mqtt');
var headless = require('headless');
var electronPath = require('electron-prebuilt');
var childProcess = require('child_process');
var portFinder = require('portfinder');
var ffmpeg = require('fluent-ffmpeg');
var moment = require('moment');
var m3u8 = require("m3u8");
var fs = require("fs");
var PouchDB = require('pouchdb');

var recordingTopic = "recording";
var mqttClientInstance = mqtt.connect("mqtt://localhost:1883", {clientId: recordingTopic});
mqttClientInstance.on('connect', function () {
    console.log("connect mqtt server success");
});
mqttClientInstance.on('error',function(error) {
    console.log("mqtt connect failed: ", error);
});
mqttClientInstance.subscribe(recordingTopic);

mqttClientInstance.on('message', function(messageTopic, data) {
    var msg = JSON.parse(data);
    var options = {
        display: {width: 1366, height: 768, depth: 24}
    };
    headless(options, function(err, xvfbChildProcess, servernum) {
        // childProcess is a ChildProcess, as returned from child_process.spawn()
        console.log('Xvfb running on server number', servernum);
        console.log('Xvfb pid', xvfbChildProcess.pid);
        console.log('err should be null', err);
        var displayOpt = ":"+servernum+".0";

        // spawn electron after xvfb has been started
        var electronChild = childProcess.spawn(electronPath, [__dirname+"/electron_app"], {env: {DISPLAY: displayOpt, TopicToSubscribe: data}});
        electronChild.stderr.on('data', function(data){
            process.stdout.write(data.toString());
        });

        portFinder.getPort(function (err, port) {
            console.log("got free port: "+port);
            function ffmpegLog(data){
                console.log(data);
            }
            function ffmpegOutput(command){
                command
                    .audioCodec("aac")
                    .videoCodec("libx264")
                    .outputOptions(["-pix_fmt yuv420p", "-tune zerolatency", "-crf 28", "-hls_time 10", "-hls_list_size 0","-threads 0", "-shortest"]);
            }
            var recordingFileName = msg.teacherTopic+"-"+msg.type+"-"+moment().format("YYYYMMDDHHmmss");
            var dirName = null;
            if(msg.type === "tutor-video" || msg.type === "answer-video"){
                dirName = "video-recording";
            }
            var recordingFilePath = "/var/lib/"+dirName+"/"+recordingFileName;
            var ffmpegCommand = ffmpeg({logger: {debug: ffmpegLog, info: ffmpegLog, warn: ffmpegLog, error: ffmpegLog}});
            ffmpegCommand
                .input("tcp://localhost:"+port+"?listen=1")
                .input(displayOpt)
                .inputFormat("x11grab")
                .inputOptions(["-itsoffset 5", "-framerate 25", "-video_size 1366x768", "-draw_mouse 0"])
                .output(recordingFilePath+"-desktop"+".m3u8")
                .size("1280x720")
                .preset(ffmpegOutput)
                .output(recordingFilePath+"-tablet"+".m3u8")
                .size("640x360")
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 1000K", "-bufsize 2000K"])
                .output(recordingFilePath+"-smartphone"+".m3u8")
                .size("480x320")
                .autopad()
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 500K", "-bufsize 1000K"])
                .on("error", function(err, stdout, stderr){
                    console.log("got error from ffmpeg: "+err.message);
                    console.log("ffmpeg stderr: "+stderr);
                })
                .on("start", function(command){
					console.log(command);
					mqttClientInstance.publish(msg.clientId, JSON.stringify({recording: "Port", port: port}));
				})
                .on("end", function(){
                    console.log("ffmpeg ended!!!");
                    electronChild.kill();
                    xvfbChildProcess.kill();
                    var m3u8Content = m3u8.M3U.create();
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-desktop"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 2001000,
                        RESOLUTION: "1280x720"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-tablet"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 1001000,
                        RESOLUTION: "640x360"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-smartphone"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 510000,
                        RESOLUTION: "480x320"
                    });
                    fs.writeFile(recordingFilePath+".m3u8", m3u8Content.toString(), null, function(err){
                        if(err === null){
                            ffmpeg.ffprobe(recordingFilePath+".m3u8", function(err, metadata){
                                var db = new PouchDB("http://localhost:5984/"+
                                    msg.teacherTopic.slice(0, msg.teacherTopic.lastIndexOf("-", msg.teacherTopic.length - 1))+
                                    "%2F"+
                                    msg.studentTopics[0].slice(0, msg.studentTopics[0].lastIndexOf("-", msg.studentTopics[0].length - 1)));
                                db.get(msg.docId, null, function(err, result){
                                    result.duration = metadata.format.duration;
                                    result.recordingFileName = recordingFileName;
                                    result.syncStatus = [false, false];
                                    db.put(result, function(){
                                        //TODO: if teacher or student is offline, then don't need to send msg
                                        var replyMsg = {
                                            chat: "NewMessage",
                                            docId: msg.docId,
                                            clientId: msg.studentTopics[0]
                                        };
                                        mqttClientInstance.publish(msg.teacherTopic, JSON.stringify(replyMsg));
                                        replyMsg.clientId = msg.teacherTopic;
                                        mqttClientInstance.publish(msg.studentTopics[0], JSON.stringify(replyMsg));
                                    });
                                });
                            });
                        }
                    });
                })
                .run();
        });
    });
});
/* when got exit signal, then exit
mqttClientInstance.end();
mqttClientInstance = null;
console.log("mqtt client has been destroyed");
*/<|endoftext|>


<commit_before>/**
 * Created by khejing on 2015/6/30.
 */

var mqtt = require('mqtt');
var headless = require('headless');
var electronPath = require('electron-prebuilt');
var childProcess = require('child_process');
var portFinder = require('portfinder');
var ffmpeg = require('fluent-ffmpeg');
var moment = require('moment');
var m3u8 = require("m3u8");
var fs = require("fs");
var PouchDB = require('pouchdb');

var recordingTopic = "recording";
var mqttClientInstance = mqtt.connect("mqtt://localhost:1883", {clientId: recordingTopic});
mqttClientInstance.on('connect', function () {
    console.log("connect mqtt server success");
});
mqttClientInstance.on('error',function(error) {
    console.log("mqtt connect failed: ", error);
});
mqttClientInstance.subscribe(recordingTopic);

mqttClientInstance.on('message', function(messageTopic, data) {
    var msg = JSON.parse(data);
    var options = {
        display: {width: 1366, height: 768, depth: 24}
    };
    headless(options, function(err, xvfbChildProcess, servernum) {
        // childProcess is a ChildProcess, as returned from child_process.spawn()
        console.log('Xvfb running on server number', servernum);
        console.log('Xvfb pid', xvfbChildProcess.pid);
        console.log('err should be null', err);
        var displayOpt = ":"+servernum+".0";

        // spawn electron after xvfb has been started
        var electronChild = childProcess.spawn(electronPath, [__dirname+"/electron_app"], {env: {DISPLAY: displayOpt, TopicToSubscribe: data}});
        electronChild.stderr.on('data', function(data){
            process.stdout.write(data.toString());
        });

        portFinder.getPort(function (err, port) {
            console.log("got free port: "+port);
            function ffmpegLog(data){
                console.log(data);
            }
            function ffmpegOutput(command){
                command
                    .audioCodec("aac")
                    .videoCodec("libx264")
                    .outputOptions(["-pix_fmt yuv420p", "-tune zerolatency", "-crf 28", "-g 50", "-hls_time 10", "-threads 0", "-shortest"]);
            }
            var recordingFileName = msg.teacherTopic+"-"+msg.type+"-"+moment().format("YYYYMMDDHHmmss");
            var dirName = null;
            if(msg.type === "tutor-video" || msg.type === "answer-video"){
                dirName = "video-recording";
            }
            var recordingFilePath = "/var/lib/"+dirName+"/"+recordingFileName;
            var ffmpegCommand = ffmpeg({logger: {debug: ffmpegLog, info: ffmpegLog, warn: ffmpegLog, error: ffmpegLog}});
            ffmpegCommand
                .input("tcp://localhost:"+port+"?listen=1")
                .input(displayOpt)
                .inputFormat("x11grab")
                .inputFPS(25)
                .inputOptions(["-itsoffset 30", "-video_size 1366x768", "-draw_mouse 0"])
                .output(recordingFilePath+"-desktop"+".m3u8")
                .size("1280x720")
                .preset(ffmpegOutput)
                .output(recordingFilePath+"-tablet"+".m3u8")
                .size("640x360")
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 1000K", "-bufsize 2000K"])
                .output(recordingFilePath+"-smartphone"+".m3u8")
                .size("480x320")
                .autopad()
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 500K", "-bufsize 1000K"])
                .on("error", function(err, stdout, stderr){
                    console.log("got error from ffmpeg: "+err.message);
                    console.log("ffmpeg stderr: "+stderr);
                })
                .on("start", function(command){
					console.log(command);
					mqttClientInstance.publish(msg.clientId, JSON.stringify({recording: "Port", port: port}));
				})
                .on("end", function(){
                    console.log("ffmpeg ended!!!");
                    electronChild.kill();
                    xvfbChildProcess.kill();
                    var m3u8Content = m3u8.M3U.create();
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-desktop"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 2001000,
                        RESOLUTION: "1280x720"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-tablet"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 1001000,
                        RESOLUTION: "640x360"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-smartphone"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 510000,
                        RESOLUTION: "480x320"
                    });
                    fs.writeFile(recordingFilePath+".m3u8", m3u8Content.toString(), null, function(err){
                        if(err === null){
                            ffmpeg.ffprobe(recordingFilePath+".m3u8", function(err, metadata){
                                var db = new PouchDB("http://localhost:5984/"+
                                    msg.teacherTopic.slice(0, msg.teacherTopic.lastIndexOf("-", msg.teacherTopic.length - 1))+
                                    "%2F"+
                                    msg.studentTopics[0].slice(0, msg.studentTopics[0].lastIndexOf("-", msg.studentTopics[0].length - 1)));
                                db.get(msg.docId, null, function(err, result){
                                    result.duration = metadata.format.duration;
                                    result.recordingFileName = recordingFileName;
                                    result.syncStatus = [false, false];
                                    db.put(result, function(){
                                        //TODO: if teacher or student is offline, then don't need to send msg
                                        var replyMsg = {
                                            chat: "NewMessage",
                                            docId: msg.docId,
                                            clientId: msg.studentTopics[0]
                                        };
                                        mqttClientInstance.publish(msg.teacherTopic, JSON.stringify(replyMsg));
                                        replyMsg.clientId = msg.teacherTopic;
                                        mqttClientInstance.publish(msg.studentTopics[0], JSON.stringify(replyMsg));
                                    });
                                });
                            });
                        }
                    });
                })
                .run();
        });
    });
});
/* when got exit signal, then exit
mqttClientInstance.end();
mqttClientInstance = null;
console.log("mqtt client has been destroyed");
*/<commit_msg>把gop大小设置去掉试试<commit_after>/**
 * Created by khejing on 2015/6/30.
 */

var mqtt = require('mqtt');
var headless = require('headless');
var electronPath = require('electron-prebuilt');
var childProcess = require('child_process');
var portFinder = require('portfinder');
var ffmpeg = require('fluent-ffmpeg');
var moment = require('moment');
var m3u8 = require("m3u8");
var fs = require("fs");
var PouchDB = require('pouchdb');

var recordingTopic = "recording";
var mqttClientInstance = mqtt.connect("mqtt://localhost:1883", {clientId: recordingTopic});
mqttClientInstance.on('connect', function () {
    console.log("connect mqtt server success");
});
mqttClientInstance.on('error',function(error) {
    console.log("mqtt connect failed: ", error);
});
mqttClientInstance.subscribe(recordingTopic);

mqttClientInstance.on('message', function(messageTopic, data) {
    var msg = JSON.parse(data);
    var options = {
        display: {width: 1366, height: 768, depth: 24}
    };
    headless(options, function(err, xvfbChildProcess, servernum) {
        // childProcess is a ChildProcess, as returned from child_process.spawn()
        console.log('Xvfb running on server number', servernum);
        console.log('Xvfb pid', xvfbChildProcess.pid);
        console.log('err should be null', err);
        var displayOpt = ":"+servernum+".0";

        // spawn electron after xvfb has been started
        var electronChild = childProcess.spawn(electronPath, [__dirname+"/electron_app"], {env: {DISPLAY: displayOpt, TopicToSubscribe: data}});
        electronChild.stderr.on('data', function(data){
            process.stdout.write(data.toString());
        });

        portFinder.getPort(function (err, port) {
            console.log("got free port: "+port);
            function ffmpegLog(data){
                console.log(data);
            }
            function ffmpegOutput(command){
                command
                    .audioCodec("aac")
                    .videoCodec("libx264")
                    .outputOptions(["-pix_fmt yuv420p", "-tune zerolatency", "-crf 28", "-hls_time 10", "-threads 0", "-shortest"]);
            }
            var recordingFileName = msg.teacherTopic+"-"+msg.type+"-"+moment().format("YYYYMMDDHHmmss");
            var dirName = null;
            if(msg.type === "tutor-video" || msg.type === "answer-video"){
                dirName = "video-recording";
            }
            var recordingFilePath = "/var/lib/"+dirName+"/"+recordingFileName;
            var ffmpegCommand = ffmpeg({logger: {debug: ffmpegLog, info: ffmpegLog, warn: ffmpegLog, error: ffmpegLog}});
            ffmpegCommand
                .input("tcp://localhost:"+port+"?listen=1")
                .input(displayOpt)
                .inputFormat("x11grab")
                .inputFPS(25)
                .inputOptions(["-itsoffset 30+", "-video_size 1366x768", "-draw_mouse 0"])
                .output(recordingFilePath+"-desktop"+".m3u8")
                .size("1280x720")
                .preset(ffmpegOutput)
                .output(recordingFilePath+"-tablet"+".m3u8")
                .size("640x360")
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 1000K", "-bufsize 2000K"])
                .output(recordingFilePath+"-smartphone"+".m3u8")
                .size("480x320")
                .autopad()
                .preset(ffmpegOutput)
                .outputOptions(["-maxrate 500K", "-bufsize 1000K"])
                .on("error", function(err, stdout, stderr){
                    console.log("got error from ffmpeg: "+err.message);
                    console.log("ffmpeg stderr: "+stderr);
                })
                .on("start", function(command){
					console.log(command);
					mqttClientInstance.publish(msg.clientId, JSON.stringify({recording: "Port", port: port}));
				})
                .on("end", function(){
                    console.log("ffmpeg ended!!!");
                    electronChild.kill();
                    xvfbChildProcess.kill();
                    var m3u8Content = m3u8.M3U.create();
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-desktop"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 2001000,
                        RESOLUTION: "1280x720"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-tablet"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 1001000,
                        RESOLUTION: "640x360"
                    });
                    m3u8Content.addStreamItem ({
                        uri: recordingFileName+"-smartphone"+".m3u8",
                        "PROGRAM-ID": 1,
                        BANDWIDTH: 510000,
                        RESOLUTION: "480x320"
                    });
                    fs.writeFile(recordingFilePath+".m3u8", m3u8Content.toString(), null, function(err){
                        if(err === null){
                            ffmpeg.ffprobe(recordingFilePath+".m3u8", function(err, metadata){
                                var db = new PouchDB("http://localhost:5984/"+
                                    msg.teacherTopic.slice(0, msg.teacherTopic.lastIndexOf("-", msg.teacherTopic.length - 1))+
                                    "%2F"+
                                    msg.studentTopics[0].slice(0, msg.studentTopics[0].lastIndexOf("-", msg.studentTopics[0].length - 1)));
                                db.get(msg.docId, null, function(err, result){
                                    result.duration = metadata.format.duration;
                                    result.recordingFileName = recordingFileName;
                                    result.syncStatus = [false, false];
                                    db.put(result, function(){
                                        //TODO: if teacher or student is offline, then don't need to send msg
                                        var replyMsg = {
                                            chat: "NewMessage",
                                            docId: msg.docId,
                                            clientId: msg.studentTopics[0]
                                        };
                                        mqttClientInstance.publish(msg.teacherTopic, JSON.stringify(replyMsg));
                                        replyMsg.clientId = msg.teacherTopic;
                                        mqttClientInstance.publish(msg.studentTopics[0], JSON.stringify(replyMsg));
                                    });
                                });
                            });
                        }
                    });
                })
                .run();
        });
    });
});
/* when got exit signal, then exit
mqttClientInstance.end();
mqttClientInstance = null;
console.log("mqtt client has been destroyed");
*/<|endoftext|>


<commit_before>import { graphqlReduce } from './utils';
import { navigate } from '../actions/route';
import {
  SELECTED_LOCALITY,
  SELECTED_ADDRESS,
  SET_TRANSPORT,
  SET_PROPERTY,
  SAVE_LINK_START,
  SAVE_LINK_SUCCESS,
  SAVE_LINK_ERROR,
  LINK_RESET
} from '../constants';

const formatTime = (hour, minute) => {

  let time = '';

  if (hour) {
    time += ((hour < 10 ? '0' : '') + hour);
  } else {
    time += '00';
  }

  if (minute) {
    time += ':' + ((minute < 10 ? '0' : '') + minute);
  } else {
    time += ':00';
  }

  return time;

};

export default function editLink(state = null, action) {

  const endState = { ...state };

  switch (action.type) {

    case SELECTED_LOCALITY:
      endState[action.payload.endpoint] = action.payload.locality;
      return endState;
    case SELECTED_ADDRESS:
      endState[action.payload.endpoint] = action.payload.locality;
      console.log("end state", endState, action);
      return endState;
    case SET_TRANSPORT:
      return { ...state, transport: action.payload.transport };
    case SET_PROPERTY:
      endState[action.payload.name] = action.payload.value;
      return endState;
    case LINK_RESET:
      if (action.payload.linkInstance && action.payload.linkInstance.link) {

        const { linkInstance } = action.payload;
        const { link } = linkInstance;

        let departureDate = null;
        if (linkInstance.departureDate) {
          departureDate = new Date(linkInstance.departureDate);
          departureDate.setHours(linkInstance.departureHour || 0);
          departureDate.setMinutes(linkInstance.departureMinute || 0);
        }

        let arrivalDate = null;
        if (linkInstance.arrivalDate) {
          arrivalDate = new Date(linkInstance.arrivalDate);
          arrivalDate.setHours(linkInstance.arrivalHour || 0);
          arrivalDate.setMinutes(linkInstance.arrivalMinute || 0);
        }

        return {
          ...state,
          uuid: linkInstance.uuid,
          from: link.from,
          to: link.to,
          transport: linkInstance.transport.slug,
          departureDate: departureDate, departureTime: departureDate,
          departureDescription: linkInstance.departureDescription,
          arrivalDate: arrivalDate, arrivalTime: arrivalDate,
          arrivalDescription: linkInstance.arrivalDescription || '',
          priceAmount: linkInstance.priceAmount || '', priceCurrency: linkInstance.priceCurrency,
          description: linkInstance.description || ''
        };

      } else {

        return {
          ...state,
          to: null, from: null,
          transport: null,
          departureDate: null, departureTime: null, departureDescription: '',
          arrivalDate: null, arrivalTime: null, arrivalDescription: '',
          priceAmount: '', priceCurrency: null,
          description: '',
          availabilityRating: null, departureRating: null, arrivalRating: null, awesomeRating: null
        };

      }

  }

  return graphqlReduce(
    state, action,
    {
      start: () => ({ linkInstance: null }),
      success: () => ({
        linkInstance: Object.assign(
          action.payload.linkInstance,
          { saved: (new Date()).getTime() }
        )
      }),
      error: () => ({ linkInstance: null })
    },
    SAVE_LINK_START,
    SAVE_LINK_SUCCESS,
    SAVE_LINK_ERROR
  );

}
<commit_msg>Fixed edit link data reset<commit_after>import { graphqlReduce } from './utils';
import { navigate } from '../actions/route';
import {
  SELECTED_LOCALITY,
  SELECTED_ADDRESS,
  SET_TRANSPORT,
  SET_PROPERTY,
  SAVE_LINK_START,
  SAVE_LINK_SUCCESS,
  SAVE_LINK_ERROR,
  LINK_RESET
} from '../constants';

const formatTime = (hour, minute) => {

  let time = '';

  if (hour) {
    time += ((hour < 10 ? '0' : '') + hour);
  } else {
    time += '00';
  }

  if (minute) {
    time += ':' + ((minute < 10 ? '0' : '') + minute);
  } else {
    time += ':00';
  }

  return time;

};

export default function editLink(state = null, action) {

  const endState = { ...state };

  switch (action.type) {

    case SELECTED_LOCALITY:
      endState[action.payload.endpoint] = action.payload.locality;
      return endState;
    case SELECTED_ADDRESS:
      endState[action.payload.endpoint] = action.payload.locality;
      console.log("end state", endState, action);
      return endState;
    case SET_TRANSPORT:
      return { ...state, transport: action.payload.transport };
    case SET_PROPERTY:
      endState[action.payload.name] = action.payload.value;
      return endState;
    case LINK_RESET:
      if (action.payload.linkInstance && action.payload.linkInstance.link) {

        const { linkInstance } = action.payload;
        const { link } = linkInstance;

        let departureDate = null;
        if (linkInstance.departureDate) {
          departureDate = new Date(linkInstance.departureDate);
          departureDate.setHours(linkInstance.departureHour || 0);
          departureDate.setMinutes(linkInstance.departureMinute || 0);
        }

        let arrivalDate = null;
        if (linkInstance.arrivalDate) {
          arrivalDate = new Date(linkInstance.arrivalDate);
          arrivalDate.setHours(linkInstance.arrivalHour || 0);
          arrivalDate.setMinutes(linkInstance.arrivalMinute || 0);
        }

        return {
          ...state,
          uuid: linkInstance.uuid,
          from: link.from,
          to: link.to,
          transport: linkInstance.transport.slug,
          departureDate: departureDate, departureTime: departureDate,
          departureDescription: linkInstance.departureDescription,
          departureAddress: linkInstance.departureAddress,
          departureLat: linkInstance.departureLat,
          departureLng: linkInstance.departureLng,
          availabilityRating: linkInstance.availabilityRating,
          departureRating: linkInstance.departureRating,
          arrivalRating: linkInstance.arrivalRating,
          awesomeRating: linkInstance.awesomeRating,
          arrivalDate: arrivalDate, arrivalTime: arrivalDate,
          arrivalDescription: linkInstance.arrivalDescription || '',
          arrivalAddress: linkInstance.arrivalAddress,
          arrivalLat: linkInstance.arrivalLat,
          arrivalLng: linkInstance.arrivalLng,
          priceAmount: linkInstance.priceAmount || '', priceCurrency: linkInstance.priceCurrency,
          description: linkInstance.description || ''
        };

      } else {

        return {
          ...state,
          to: null, from: null,
          transport: null,
          departureDate: null, departureTime: null, departureDescription: '',
          departureAddress: '', departureLat: null, departureLng: null,
          arrivalDate: null, arrivalTime: null, arrivalDescription: '',
          arrivalAddress: '', arrivalLat: null, arrivalLng: null,
          priceAmount: '', priceCurrency: null,
          description: '',
          availabilityRating: null, departureRating: null, arrivalRating: null, awesomeRating: null
        };

      }

  }

  return graphqlReduce(
    state, action,
    {
      start: () => ({ linkInstance: null }),
      success: () => ({
        linkInstance: Object.assign(
          action.payload.linkInstance,
          { saved: (new Date()).getTime() }
        )
      }),
      error: () => ({ linkInstance: null })
    },
    SAVE_LINK_START,
    SAVE_LINK_SUCCESS,
    SAVE_LINK_ERROR
  );

}
<|endoftext|>