<commit_before>/*
 * backbone.canal v0.1.0
 * Copyright 2013, Matt Morgan (@mlmorg)
 * MIT license
 */
(function () {

  "use strict";

  // Alias libraries
  var root = this;
  var _ = root._;
  var Backbone = root.Backbone;

  // References for overridden methods
  var _constructor = Backbone.Router.prototype.constructor;
  var _extractParameters = Backbone.Router.prototype._extractParameters;
  var _getFragment = Backbone.History.prototype.getFragment;

  // Useful regex patters
  var paramNamesPattern = /(\(.*?)?[:\*]\w+\)?/g;
  var optionalParamPattern = /\(.*?[:\*](\w+)\)/;
  var queryStringPattern = /\?.*$/;
  var plusPattern = /\+/g;
  var r20Pattern = /%20/g;
  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;

  // Backbone.Canal
  // --------------
  var Canal = Backbone.Canal = {

    configure: function (options) {
      return _.extend(this.options, options);
    },

    options: {

      deparam: function (string) {
        // Extract the key/value pairs
        var items = string.replace(plusPattern, ' ').split('&');

        // Build hash
        var obj = {};
        _.each(items, function (params) {
          var param = params.split('=');
          obj[param[0]] = decodeURIComponent(param[1]);
        });
        return obj;
      },

      param: function (obj) {
        // Build param strings
        var params = _.map(obj, function (value, key) {
          return key + '=' + encodeURIComponent(value);
        });

        // Create full query param string
        return params.join('&').replace(r20Pattern, '+');
      }

    }
  };

  // Extend Backbone.Router
  // ----------------------
  Backbone.Router = Backbone.Router.extend({

    constructor: function () {
      this._routes = {};
      this._named = {};
      return _constructor.apply(this, arguments);
    },

    route: function (route, name, callback) {
      // Store information about the route on the router
      route = this._storeRoute(route, name);

      // Default callback to the method present on the router
      if (!callback) {
        callback = this[name];
      }

      // Add the handler to Backbone.History
      Backbone.history.route(route, _.bind(function (fragment) {
        // Extract route and query parameters
        var params = this._extractParameters(route, fragment);

        // Create argument array
        var args = [params];

        // Call any before filters
        var halt = _.find(this._getFilters(name, 'before'), function (filter) {
          return filter.apply(this, [name].concat(args)) === false;
        });

        // Stop if any before filters return false
        if (halt) {
          return;
        }

        // Create a function to call the route method and trigger events
        var cb = _.bind(function () {
          // Run the callback
          if (callback) {
            callback.apply(this, args);
          }

          // Trigger events
          this.trigger.apply(this, ['route:' + name].concat(args));
          this.trigger.apply(this, ['route', name].concat(args));
          Backbone.history.trigger('route', this, name, args);

          // Call any after filters
          _.each(this._getFilters(name, 'after'), function (filter) {
            filter.apply(this, [name].concat(args));
          });
        }, this);

        // Build the around filters around the function
        // (reversed for correct order)
        _.each(this._getFilters(name, 'around').reverse(), function (filter) {
          var lastCb = cb;
          cb = _.bind(function () {
            filter.apply(this, [lastCb, name].concat(args));
          }, this);
        }, this);

        // Call the function
        cb();

      }, this));

      return this;
    },

    url: function (name, params) {
      params = params || {};

      // Determine the best match for this route with the passed params
      var routes = this._named[name] || [];
      var keys = _.keys(params);
      var route = _.find(routes, function (route) {
        var names = _.difference(route.parameters, route.optionalParameters);
        var diff = _.difference(names, keys);
        return !diff.length;
      });

      // If we have a matching route, build the URL for it
      if (route) {
        return this._buildUrl(route.route, params);
      }
    },

    go: function (name, params, options) {
      // Get the associated route URL
      var url = this.url(name, params);

      // If a URL exists, navigate to it
      if (_.isString(url)) {
        return this.navigate(url, _.extend({ trigger: true }, options));
      }

      // Otherwise, call the router method, if it exists
      else if (this[name]) {
        return this[name](params);
      }

      // When no method or matching route exists, throw an error
      else {
        throw new Error('No method or matching route exists');
      }
    },

    _extractParameters: function (route, fragment) {
      var params = {};

      // Remove any query parameters from fragment
      var query = getQueryString(fragment);
      fragment = fragment.replace(query, '');

      // Parse query parameters and merge onto hash
      if (query) {
        _.extend(params, Canal.options.deparam(query.substr(1)));
      }

      // Extract named/splat parameters and merge onto hash
      var paramNames = this._routes[route].parameters;
      var paramValues = _extractParameters.call(this, route, fragment);
      if (paramValues) {
        _.each(paramValues, function (param, i) {
          // Set the parameter key to the name in the names array or, if no
          // name is in the array, the index value
          var key = paramNames[i] || i;
          params[key] = param;
        });
      }
      return params;
    },

    _getFilters: function (name, type) {
      var filters = [];
      _.each(this[type], function (options, filterName) {
        var add = true;
        options = options || {};

        // Determine whether this filter should be used based on only option
        if (options.only) {
          add = false;
          options.only = _.isArray(options.only) ?
            options.only : [options.only];
          if (_.contains(options.only, name)) {
            add = true;
          }
        }

        // Determine whether this filter should be used based on except option
        if (options.except) {
          options.except = _.isArray(options.except) ?
            options.except : [options.except];
          if (_.contains(options.except, name)) {
            add = false;
          }
        }

        // Upon determination, add the filter to the filters array
        if (add && this[filterName]) {
          filters.push(this[filterName]);
        }
      }, this);
      return filters;
    },

    _storeRoute: function (route, name) {
      var url = route;

      // Create a regular expression of the route
      if (!_.isRegExp(route)) {
        route = this._routeToRegExp(route);
      }

      // Get route parameter names and any optionals
      var optionals = [];
      var parameters = _.map(url.match(paramNamesPattern), function (name) {
        var optional = name.match(optionalParamPattern);
        if (optional) {
          name = optional[1];
          optionals.push(name);
        } else {
          name = name.substr(1);
        }
        return name;
      });

      // Store hash of route information on the router
      this._routes[route] = {
        route: route,
        url: url !== route ? url : undefined,
        parameters: parameters,
        optionalParameters: optionals
      };

      // Add route information to an array of routes associated with a method
      this._named[name] = this._named[name] || [];
      this._named[name].push(this._routes[route]);

      // Sort the named route array by number of parameters
      this._named[name] = _.sortBy(this._named[name], function (route) {
        return -route.parameters.length;
      });

      return route;
    },

    _buildUrl: function (route, params) {
      params = _.clone(params || {});

      // Get route information
      route = this._routes[route];

      // Start with the base and leading slash
      var url = '/' + (route.url || '');

      // Replace named/splat parts with their parameter equivalent
      _.each(route.parameters, function (name) {
        // Find named/splat parts that match the passed parameter
        var match = url.match(new RegExp('(\\(.*?)?[:\\*]' + name + '\\)?'));
        if (match) {
          var value = params[name];

          // Optional parameters that don't exist on the params hash should
          // be removed
          if (!_.isString(value)) {
            value = '';
          }
          // Add any leading characters stripped out of optional parts
          else {
            if (match[1]) {
              value = match[1].substring(1) + value;
            }
          }

          // Replace url part with the parameter value
          url = url.replace(match[0], value);

          // Remove this parameter from the hash
          delete params[name];
        }
      });

      // Add any extra items as query parameters to url
      var query = Canal.options.param(params);
      if (query) {
        url += '?' + query;
      }

      return url;
    }

  });

  // Extend Backbone.History
  // -----------------------
  _.extend(Backbone.History.prototype, {

    getFragment: function (fragment, forcePushState) {
      // Get query string from current URL, if necessary
      var query, queryRegExp;
      if (!_.isString(fragment)) {
        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
          query = this.location.search;
          queryRegExp = query.replace(escapeRegExp, '\\$&');
        }
      }

      // Get fragment from original method
      fragment = _getFragment.call(this, fragment, forcePushState);

      // Add the query string, if not already present
      if (query && !fragment.match(queryRegExp)) {
        fragment += query;
      }
      return fragment;
    },

    loadUrl: function (fragmentOverride) {
      // Get fragment
      var fragment = this.fragment = this.getFragment(fragmentOverride);

      // Create fragment base without a query string
      var query = getQueryString(fragment);
      var fragmentBase = query ? fragment.replace(query, '') : fragment;

      // If a handler matches the base, run callback
      var matched = _.any(this.handlers, function (handler) {
        if (handler.route.test(fragmentBase)) {
          handler.callback(fragment);
          return true;
        }
      });
      return matched;
    }

  });

  // Helper functions
  // ----------------
  var getQueryString = function (url) {
    var query = url.match(queryStringPattern);
    if (query) {
      return query[0];
    }
  };

}).call(this);
<commit_msg>Pass router as context to filters<commit_after>/*
 * backbone.canal v0.1.0
 * Copyright 2013, Matt Morgan (@mlmorg)
 * MIT license
 */
(function () {

  "use strict";

  // Alias libraries
  var root = this;
  var _ = root._;
  var Backbone = root.Backbone;

  // References for overridden methods
  var _constructor = Backbone.Router.prototype.constructor;
  var _extractParameters = Backbone.Router.prototype._extractParameters;
  var _getFragment = Backbone.History.prototype.getFragment;

  // Useful regex patters
  var paramNamesPattern = /(\(.*?)?[:\*]\w+\)?/g;
  var optionalParamPattern = /\(.*?[:\*](\w+)\)/;
  var queryStringPattern = /\?.*$/;
  var plusPattern = /\+/g;
  var r20Pattern = /%20/g;
  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;

  // Backbone.Canal
  // --------------
  var Canal = Backbone.Canal = {

    configure: function (options) {
      return _.extend(this.options, options);
    },

    options: {

      deparam: function (string) {
        // Extract the key/value pairs
        var items = string.replace(plusPattern, ' ').split('&');

        // Build hash
        var obj = {};
        _.each(items, function (params) {
          var param = params.split('=');
          obj[param[0]] = decodeURIComponent(param[1]);
        });
        return obj;
      },

      param: function (obj) {
        // Build param strings
        var params = _.map(obj, function (value, key) {
          return key + '=' + encodeURIComponent(value);
        });

        // Create full query param string
        return params.join('&').replace(r20Pattern, '+');
      }

    }
  };

  // Extend Backbone.Router
  // ----------------------
  Backbone.Router = Backbone.Router.extend({

    constructor: function () {
      this._routes = {};
      this._named = {};
      return _constructor.apply(this, arguments);
    },

    route: function (route, name, callback) {
      // Store information about the route on the router
      route = this._storeRoute(route, name);

      // Default callback to the method present on the router
      if (!callback) {
        callback = this[name];
      }

      // Add the handler to Backbone.History
      Backbone.history.route(route, _.bind(function (fragment) {
        // Extract route and query parameters
        var params = this._extractParameters(route, fragment);

        // Create argument array
        var args = [params];

        // Call any before filters
        var halt = _.find(this._getFilters(name, 'before'), function (filter) {
          return filter.apply(this, [name].concat(args)) === false;
        }, this);

        // Stop if any before filters return false
        if (halt) {
          return;
        }

        // Create a function to call the route method and trigger events
        var cb = _.bind(function () {
          // Run the callback
          if (callback) {
            callback.apply(this, args);
          }

          // Trigger events
          this.trigger.apply(this, ['route:' + name].concat(args));
          this.trigger.apply(this, ['route', name].concat(args));
          Backbone.history.trigger('route', this, name, args);

          // Call any after filters
          _.each(this._getFilters(name, 'after'), function (filter) {
            filter.apply(this, [name].concat(args));
          }, this);
        }, this);

        // Build the around filters around the function
        // (reversed for correct order)
        _.each(this._getFilters(name, 'around').reverse(), function (filter) {
          var lastCb = cb;
          cb = _.bind(function () {
            filter.apply(this, [lastCb, name].concat(args));
          }, this);
        }, this);

        // Call the function
        cb();

      }, this));

      return this;
    },

    url: function (name, params) {
      params = params || {};

      // Determine the best match for this route with the passed params
      var routes = this._named[name] || [];
      var keys = _.keys(params);
      var route = _.find(routes, function (route) {
        var names = _.difference(route.parameters, route.optionalParameters);
        var diff = _.difference(names, keys);
        return !diff.length;
      });

      // If we have a matching route, build the URL for it
      if (route) {
        return this._buildUrl(route.route, params);
      }
    },

    go: function (name, params, options) {
      // Get the associated route URL
      var url = this.url(name, params);

      // If a URL exists, navigate to it
      if (_.isString(url)) {
        return this.navigate(url, _.extend({ trigger: true }, options));
      }

      // Otherwise, call the router method, if it exists
      else if (this[name]) {
        return this[name](params);
      }

      // When no method or matching route exists, throw an error
      else {
        throw new Error('No method or matching route exists');
      }
    },

    _extractParameters: function (route, fragment) {
      var params = {};

      // Remove any query parameters from fragment
      var query = getQueryString(fragment);
      fragment = fragment.replace(query, '');

      // Parse query parameters and merge onto hash
      if (query) {
        _.extend(params, Canal.options.deparam(query.substr(1)));
      }

      // Extract named/splat parameters and merge onto hash
      var paramNames = this._routes[route].parameters;
      var paramValues = _extractParameters.call(this, route, fragment);
      if (paramValues) {
        _.each(paramValues, function (param, i) {
          // Set the parameter key to the name in the names array or, if no
          // name is in the array, the index value
          var key = paramNames[i] || i;
          params[key] = param;
        });
      }
      return params;
    },

    _getFilters: function (name, type) {
      var filters = [];
      _.each(this[type], function (options, filterName) {
        var add = true;
        options = options || {};

        // Determine whether this filter should be used based on only option
        if (options.only) {
          add = false;
          options.only = _.isArray(options.only) ?
            options.only : [options.only];
          if (_.contains(options.only, name)) {
            add = true;
          }
        }

        // Determine whether this filter should be used based on except option
        if (options.except) {
          options.except = _.isArray(options.except) ?
            options.except : [options.except];
          if (_.contains(options.except, name)) {
            add = false;
          }
        }

        // Upon determination, add the filter to the filters array
        if (add && this[filterName]) {
          filters.push(this[filterName]);
        }
      }, this);
      return filters;
    },

    _storeRoute: function (route, name) {
      var url = route;

      // Create a regular expression of the route
      if (!_.isRegExp(route)) {
        route = this._routeToRegExp(route);
      }

      // Get route parameter names and any optionals
      var optionals = [];
      var parameters = _.map(url.match(paramNamesPattern), function (name) {
        var optional = name.match(optionalParamPattern);
        if (optional) {
          name = optional[1];
          optionals.push(name);
        } else {
          name = name.substr(1);
        }
        return name;
      });

      // Store hash of route information on the router
      this._routes[route] = {
        route: route,
        url: url !== route ? url : undefined,
        parameters: parameters,
        optionalParameters: optionals
      };

      // Add route information to an array of routes associated with a method
      this._named[name] = this._named[name] || [];
      this._named[name].push(this._routes[route]);

      // Sort the named route array by number of parameters
      this._named[name] = _.sortBy(this._named[name], function (route) {
        return -route.parameters.length;
      });

      return route;
    },

    _buildUrl: function (route, params) {
      params = _.clone(params || {});

      // Get route information
      route = this._routes[route];

      // Start with the base and leading slash
      var url = '/' + (route.url || '');

      // Replace named/splat parts with their parameter equivalent
      _.each(route.parameters, function (name) {
        // Find named/splat parts that match the passed parameter
        var match = url.match(new RegExp('(\\(.*?)?[:\\*]' + name + '\\)?'));
        if (match) {
          var value = params[name];

          // Optional parameters that don't exist on the params hash should
          // be removed
          if (!_.isString(value)) {
            value = '';
          }
          // Add any leading characters stripped out of optional parts
          else {
            if (match[1]) {
              value = match[1].substring(1) + value;
            }
          }

          // Replace url part with the parameter value
          url = url.replace(match[0], value);

          // Remove this parameter from the hash
          delete params[name];
        }
      });

      // Add any extra items as query parameters to url
      var query = Canal.options.param(params);
      if (query) {
        url += '?' + query;
      }

      return url;
    }

  });

  // Extend Backbone.History
  // -----------------------
  _.extend(Backbone.History.prototype, {

    getFragment: function (fragment, forcePushState) {
      // Get query string from current URL, if necessary
      var query, queryRegExp;
      if (!_.isString(fragment)) {
        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
          query = this.location.search;
          queryRegExp = query.replace(escapeRegExp, '\\$&');
        }
      }

      // Get fragment from original method
      fragment = _getFragment.call(this, fragment, forcePushState);

      // Add the query string, if not already present
      if (query && !fragment.match(queryRegExp)) {
        fragment += query;
      }
      return fragment;
    },

    loadUrl: function (fragmentOverride) {
      // Get fragment
      var fragment = this.fragment = this.getFragment(fragmentOverride);

      // Create fragment base without a query string
      var query = getQueryString(fragment);
      var fragmentBase = query ? fragment.replace(query, '') : fragment;

      // If a handler matches the base, run callback
      var matched = _.any(this.handlers, function (handler) {
        if (handler.route.test(fragmentBase)) {
          handler.callback(fragment);
          return true;
        }
      });
      return matched;
    }

  });

  // Helper functions
  // ----------------
  var getQueryString = function (url) {
    var query = url.match(queryStringPattern);
    if (query) {
      return query[0];
    }
  };

}).call(this);
<|endoftext|>


<commit_before>var debug = require('debug')('bleno');

var events = require('events');
var os = require('os');
var util = require('util');

var UuidUtil = require('./uuid-util');

var PrimaryService = require('./primary-service');
var Characteristic = require('./characteristic');
var Descriptor = require('./descriptor');

var bindings = null;

var platform = os.platform();

if (platform === 'darwin') {
  bindings = require('./mac/bindings');
} else if (platform === 'linux') {
  bindings = require('./linux/bindings');
} else {
  throw new Error('Unsupported platform');
}

function Bleno() {
  this.state = 'unknown';
  this.rssi = 0;

  this._bindings = bindings;

  this._bindings.on('stateChange', this.onStateChange.bind(this));
  this._bindings.on('advertisingStart', this.onAdvertisingStart.bind(this));
  this._bindings.on('advertisingStop', this.onAdvertisingStop.bind(this));
  this._bindings.on('servicesSet', this.onServicesSet.bind(this));
  this._bindings.on('accept', this.onAccept.bind(this));
  this._bindings.on('disconnect', this.onDisconnect.bind(this));

  this._bindings.on('rssiUpdate', this.onRssiUpdate.bind(this));
}

util.inherits(Bleno, events.EventEmitter);

Bleno.prototype.PrimaryService = PrimaryService;
Bleno.prototype.Characteristic = Characteristic;
Bleno.prototype.Descriptor = Descriptor;

Bleno.prototype.onStateChange = function(state) {
  debug('stateChange ' + state);

  this.state = state;

  this.emit('stateChange', state);
};

Bleno.prototype.onAccept = function() {
  debug('accept');
  this.emit('accept');
};

Bleno.prototype.onDisconnect = function() {
  debug('disconnect');
  this.emit('disconnect');
};

Bleno.prototype.startAdvertising = function(name, serviceUuids, callback) {
  if (callback) {
    this.once('advertisingStart', callback);
  }

  var undashedServiceUuids = [];

  if (serviceUuids && serviceUuids.length) {
    for (var i = 0; i < serviceUuids.length; i++) {
      undashedServiceUuids[i] = UuidUtil.removeDashes(serviceUuids[i]);
    }
  }

  this._bindings.startAdvertising(name, undashedServiceUuids);
};

Bleno.prototype.startAdvertisingIBeacon = function(uuid, major, minor, measuredPower, callback) {
  var uuidData = new Buffer(uuid, 'hex');
  var uuidDataLength = uuidData.length;
  var iBeaconData = new Buffer(uuidData.length + 5);

  for (var i = 0; i < uuidDataLength; i++) {
    iBeaconData[i] = uuidData[i];
  }

  iBeaconData.writeUInt16BE(major, uuidDataLength);
  iBeaconData.writeUInt16BE(minor, uuidDataLength + 2);
  iBeaconData.writeInt8(measuredPower, uuidDataLength + 4);

  if (callback) {
    this.once('advertisingStart', callback);
  }

  debug('iBeacon data = ' + iBeaconData.toString('hex'));

  this._bindings.startAdvertisingIBeacon(iBeaconData);
};

Bleno.prototype.onAdvertisingStart = function(error) {
  debug('advertisingStart: ' + error);

  if (error) {
    this.emit('advertisingStartError', error);
  }

  this.emit('advertisingStart', error);
};

if (platform === 'linux') {
  // Linux only API
  Bleno.prototype.startAdvertisingWithEIRData = function(advertisementData, scanData, callback) {
    if (callback) {
      this.once('advertisingStart', callback);
    }
    this._bindings.startAdvertisingWithEIRData(advertisementData, scanData);
  };
}

Bleno.prototype.stopAdvertising = function(callback) {
  if (callback) {
    this.once('advertisingStop', callback);
  }
  this._bindings.stopAdvertising();
};

Bleno.prototype.onAdvertisingStop = function() {
  debug('advertisingStop');
  this.emit('advertisingStop');
};

Bleno.prototype.setServices = function(services, callback) {
  if (callback) {
    this.once('servicesSet', callback);
  }
  this._bindings.setServices(services);
};

Bleno.prototype.onServicesSet = function() {
  debug('servicesSet');
  this.emit('servicesSet');
};

if (platform === 'linux') {
  // Linux only API
  Bleno.prototype.disconnect = function() {
    debug('disconnect');
    this._bindings.disconnect();
  };

  Bleno.prototype.updateRssi = function(callback) {
    if (callback) {
      this.once('rssiUpdate', function(rssi) {
        callback(null, rssi);
      });
    }

    this._bindings.updateRssi();
  };
}

Bleno.prototype.onRssiUpdate = function(rssi) {
  this.emit('rssiUpdate', rssi);
};

module.exports = Bleno;
<commit_msg>- support dashed uuids for iBeacon advertisement<commit_after>var debug = require('debug')('bleno');

var events = require('events');
var os = require('os');
var util = require('util');

var UuidUtil = require('./uuid-util');

var PrimaryService = require('./primary-service');
var Characteristic = require('./characteristic');
var Descriptor = require('./descriptor');

var bindings = null;

var platform = os.platform();

if (platform === 'darwin') {
  bindings = require('./mac/bindings');
} else if (platform === 'linux') {
  bindings = require('./linux/bindings');
} else {
  throw new Error('Unsupported platform');
}

function Bleno() {
  this.state = 'unknown';
  this.rssi = 0;

  this._bindings = bindings;

  this._bindings.on('stateChange', this.onStateChange.bind(this));
  this._bindings.on('advertisingStart', this.onAdvertisingStart.bind(this));
  this._bindings.on('advertisingStop', this.onAdvertisingStop.bind(this));
  this._bindings.on('servicesSet', this.onServicesSet.bind(this));
  this._bindings.on('accept', this.onAccept.bind(this));
  this._bindings.on('disconnect', this.onDisconnect.bind(this));

  this._bindings.on('rssiUpdate', this.onRssiUpdate.bind(this));
}

util.inherits(Bleno, events.EventEmitter);

Bleno.prototype.PrimaryService = PrimaryService;
Bleno.prototype.Characteristic = Characteristic;
Bleno.prototype.Descriptor = Descriptor;

Bleno.prototype.onStateChange = function(state) {
  debug('stateChange ' + state);

  this.state = state;

  this.emit('stateChange', state);
};

Bleno.prototype.onAccept = function() {
  debug('accept');
  this.emit('accept');
};

Bleno.prototype.onDisconnect = function() {
  debug('disconnect');
  this.emit('disconnect');
};

Bleno.prototype.startAdvertising = function(name, serviceUuids, callback) {
  if (callback) {
    this.once('advertisingStart', callback);
  }

  var undashedServiceUuids = [];

  if (serviceUuids && serviceUuids.length) {
    for (var i = 0; i < serviceUuids.length; i++) {
      undashedServiceUuids[i] = UuidUtil.removeDashes(serviceUuids[i]);
    }
  }

  this._bindings.startAdvertising(name, undashedServiceUuids);
};

Bleno.prototype.startAdvertisingIBeacon = function(uuid, major, minor, measuredPower, callback) {
  var undashedUuid =  UuidUtil.removeDashes(uuid);
  var uuidData = new Buffer(undashedUuid, 'hex');
  var uuidDataLength = uuidData.length;
  var iBeaconData = new Buffer(uuidData.length + 5);

  for (var i = 0; i < uuidDataLength; i++) {
    iBeaconData[i] = uuidData[i];
  }

  iBeaconData.writeUInt16BE(major, uuidDataLength);
  iBeaconData.writeUInt16BE(minor, uuidDataLength + 2);
  iBeaconData.writeInt8(measuredPower, uuidDataLength + 4);

  if (callback) {
    this.once('advertisingStart', callback);
  }

  debug('iBeacon data = ' + iBeaconData.toString('hex'));

  this._bindings.startAdvertisingIBeacon(iBeaconData);
};

Bleno.prototype.onAdvertisingStart = function(error) {
  debug('advertisingStart: ' + error);

  if (error) {
    this.emit('advertisingStartError', error);
  }

  this.emit('advertisingStart', error);
};

if (platform === 'linux') {
  // Linux only API
  Bleno.prototype.startAdvertisingWithEIRData = function(advertisementData, scanData, callback) {
    if (callback) {
      this.once('advertisingStart', callback);
    }
    this._bindings.startAdvertisingWithEIRData(advertisementData, scanData);
  };
}

Bleno.prototype.stopAdvertising = function(callback) {
  if (callback) {
    this.once('advertisingStop', callback);
  }
  this._bindings.stopAdvertising();
};

Bleno.prototype.onAdvertisingStop = function() {
  debug('advertisingStop');
  this.emit('advertisingStop');
};

Bleno.prototype.setServices = function(services, callback) {
  if (callback) {
    this.once('servicesSet', callback);
  }
  this._bindings.setServices(services);
};

Bleno.prototype.onServicesSet = function() {
  debug('servicesSet');
  this.emit('servicesSet');
};

if (platform === 'linux') {
  // Linux only API
  Bleno.prototype.disconnect = function() {
    debug('disconnect');
    this._bindings.disconnect();
  };

  Bleno.prototype.updateRssi = function(callback) {
    if (callback) {
      this.once('rssiUpdate', function(rssi) {
        callback(null, rssi);
      });
    }

    this._bindings.updateRssi();
  };
}

Bleno.prototype.onRssiUpdate = function(rssi) {
  this.emit('rssiUpdate', rssi);
};

module.exports = Bleno;
<|endoftext|>


<commit_before>const $ = require('jquery')
const _ = require('lodash')

var canvas    = document.getElementById('canvas');
var context   = canvas.getContext('2d');
// var direction = 'right';
var direction = '';
var wall = [];

var block = new Block(10,10, 5, 5, canvas, context);

function Block(x, y, width, height, canvas, context) {
  this.x       = x;
  this.y       = y;
  this.width   = width;
  this.height  = height;
  this.canvas  = canvas;
  this.context = context;
}

Block.prototype.move = function (direction) {

  switch (direction) {
    case 'up':
      checkTopBoundry(this);
      break;
    case 'down':
      checkBottomBoundry(this);
      break;
    case 'left':
      checkLeftBoundry(this);
      break;
    case 'right':
      checkRightBoundry(this);
      break;
  }
  return this;
};

Block.prototype.draw = function () {

  this.context.fillRect(this.x, this.y, this.width, this.height);
  this.context.fillStyle="#31FDE8";
  return this;
};

window.onload = function() {

  document.addEventListener('keydown', function(event) {
    direction = getDirection(event)
  }, false);

}

function getDirection(event) {
  switch (event.keyCode) {
    case 37:
      console.log('left')
      return 'left'
      break;
    case 38:
      console.log('up')
      return 'up'
      break;
    case 39:
      console.log('right')
      return 'right'
      break;
    case 40:
      console.log('down')
      return 'down'
      break;
  }

}

function checkLeftBoundry (_this) {

  if((_this.x - 1) < 0) {
    return _this.x = 600;
  } else {
    console.log([_this.x, _this.y]);
    return _this.x--;
  }
};

function checkRightBoundry (_this) {

  if((_this.x + 1) > 600) {
    return _this.x = 0;
  } else {
    console.log([_this.x, _this.y]);
    return _this.x++;
  }
};

function checkTopBoundry (_this) {

  if((_this.y - 1) < 0) {
    return _this.y = 400;
  } else {
    console.log([_this.x, _this.y]);
    return _this.y--;
  }
};

function checkBottomBoundry (_this) {

  if((_this.y + 1) > 400) {
    return _this.y = 0;
  } else {
    console.log([_this.x, _this.y]);
    return _this.y++;
  }
};

requestAnimationFrame(function gameLoop() {

  if (_.find(wall, [block.x, block.y]) === undefined) {
    wall.push([block.x, block.y]);
  }

  block.move(direction).draw();
  collisionCheck(block);

  requestAnimationFrame(gameLoop);
});

function collisionCheck(block) {

  if (_.some(wall, [block.x, block.y])) {
   return console.log("game over");
  }
  return console.log('still alive')
};

module.exports = Block;
<commit_msg>add game stop on collision<commit_after>const $ = require('jquery')
const _ = require('lodash')

var canvas    = document.getElementById('canvas');
var context   = canvas.getContext('2d');
var direction = 'right';
var wall = [];

var block = new Block(10,10, 5, 5, canvas, context);

function Block(x, y, width, height, canvas, context) {
  this.x       = x;
  this.y       = y;
  this.width   = width;
  this.height  = height;
  this.canvas  = canvas;
  this.context = context;
}

Block.prototype.move = function (direction) {

  switch (direction) {
    case 'up':
      checkTopBoundry(this);
      break;
    case 'down':
      checkBottomBoundry(this);
      break;
    case 'left':
      checkLeftBoundry(this);
      break;
    case 'right':
      checkRightBoundry(this);
      break;
  }
  return this;
};

Block.prototype.draw = function () {

  this.context.fillRect(this.x, this.y, this.width, this.height);
  this.context.fillStyle="#31FDE8";
  return this;
};

window.onload = function() {

  document.addEventListener('keydown', function(event) {
    direction = getDirection(event)
  }, false);

}

function getDirection(event) {
  switch (event.keyCode) {
    case 37:
      console.log('left')
      return 'left'
      break;
    case 38:
      console.log('up')
      return 'up'
      break;
    case 39:
      console.log('right')
      return 'right'
      break;
    case 40:
      console.log('down')
      return 'down'
      break;
  }

}

function checkLeftBoundry (_this) {

  if((_this.x - 1) < 0) {
    return _this.x = 600;
  } else {
    console.log([_this.x, _this.y]);
    return _this.x--;
  }
};

function checkRightBoundry (_this) {

  if((_this.x + 1) > 600) {
    return _this.x = 0;
  } else {
    console.log([_this.x, _this.y]);
    return _this.x++;
  }
};

function checkTopBoundry (_this) {

  if((_this.y - 1) < 0) {
    return _this.y = 400;
  } else {
    console.log([_this.x, _this.y]);
    return _this.y--;
  }
};

function checkBottomBoundry (_this) {

  if((_this.y + 1) > 400) {
    return _this.y = 0;
  } else {
    console.log([_this.x, _this.y]);
    return _this.y++;
  }
};

requestAnimationFrame(function gameLoop() {

  if (_.find(wall, [block.x, block.y]) === undefined) {
    wall.push([block.x, block.y]);
  }

  block.move(direction).draw();

  if ( collisionCheck(block)){
    cosole.log('game over!');
  }

  requestAnimationFrame(gameLoop);
});

function collisionCheck(block) {

  if (_.some(wall, [block.x, block.y])) {
    return 'game over'
  }

};

module.exports = Block;
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var path = require('path');
var slash = require('slash');

var Block = function (config, file, match) {
    this.replacement = match[0];
    this.linefeed = match[1];
    this.indent = match[2];
    this.beginTag = match[3];
    this.taskName = match[4];
    this.originalContent = match[5];
    this.endTag = match[6];

    this.replacements = [];
    this.config = config;
    this.template = null;
    this.file = file;
};

Block.prototype.build = function () {
    if (!this.replacements.length) {
        return this.config.keepUnassigned ? [this.originalContent] : [];
    }

    // get the replacement strings and do replacements for extensions
    if (this.uniqueExts) {
        var basename = path.basename(this.file.path);
        var extname = path.extname(basename);
        basename = basename.slice(0, basename.lastIndexOf(extname));
        if (this.uniqueExts['%f']) {
            this.uniqueExts['%f'].value = basename;
        }
        if (this.uniqueExts['%e']) {
            this.uniqueExts['%e'].value = extname;
        }

        Object.keys(this.uniqueExts).forEach(function (key) {
            var unique = this.uniqueExts[key];
            this.template = this.template.replace(unique.regex, unique.value);
        }.bind(this));
    }

    if (this.srcIsNull) {
        return [this.indent + this.template];
    }

    return this.replacements.map(function (replacement) {
        if (this.template) {
            if (Array.isArray(replacement)) {
                replacement.unshift(this.template);
                return this.indent + util.format.apply(util, replacement);
            } else {
                return this.indent + util.format(this.template, replacement);
            }
        }

        if (this.config.resolvePaths) {
            var replacementPath = path.resolve(this.file.cwd, replacement);
            replacement = path.relative(this.file.dirname, replacementPath);
            replacement = slash(replacement);
        }

        var ext = replacement.split('.').pop().toLowerCase();

        //add build version or timestamp support
        //some file like main.js?ts=123124
        //some file like main.js?sha1=0a9d
        ext = ext.split('?')[0].toLowerCase();

        if (ext === 'js') {
            return util.format('%s<script src="%s"></script>', this.indent, replacement);
        } else if (ext === 'css') {
            return util.format('%s<link rel="stylesheet" href="%s">', this.indent, replacement);
        }
        return this.indent + replacement;
    }.bind(this));
};

Block.prototype.compile = function (tasks) {
    var task = tasks[this.taskName];

    if (task) {
        this.replacements = task.src;
        this.template = task.tpl;
        this.uniqueExts = task.uni;
        this.srcIsNull = task.srcIsNull;
    }

    var buildResult = this.build();

    if (this.config.keepBlockTags) {
        buildResult.unshift(this.indent + this.beginTag);
        buildResult.push(this.indent + this.endTag);
    }

    buildResult.unshift(null);
    buildResult.push(null);

    return buildResult.join(this.linefeed);
};

module.exports = Block;
<commit_msg>file.dirname is only available in vinyl@0.5.0 and newer, using path.dirname to support the older versions.<commit_after>'use strict';

var util = require('util');
var path = require('path');
var slash = require('slash');

var Block = function (config, file, match) {
    this.replacement = match[0];
    this.linefeed = match[1];
    this.indent = match[2];
    this.beginTag = match[3];
    this.taskName = match[4];
    this.originalContent = match[5];
    this.endTag = match[6];

    this.replacements = [];
    this.config = config;
    this.template = null;
    this.file = file;
};

Block.prototype.build = function () {
    if (!this.replacements.length) {
        return this.config.keepUnassigned ? [this.originalContent] : [];
    }

    // get the replacement strings and do replacements for extensions
    if (this.uniqueExts) {
        var basename = path.basename(this.file.path);
        var extname = path.extname(basename);
        basename = basename.slice(0, basename.lastIndexOf(extname));
        if (this.uniqueExts['%f']) {
            this.uniqueExts['%f'].value = basename;
        }
        if (this.uniqueExts['%e']) {
            this.uniqueExts['%e'].value = extname;
        }

        Object.keys(this.uniqueExts).forEach(function (key) {
            var unique = this.uniqueExts[key];
            this.template = this.template.replace(unique.regex, unique.value);
        }.bind(this));
    }

    if (this.srcIsNull) {
        return [this.indent + this.template];
    }

    return this.replacements.map(function (replacement) {
        if (this.template) {
            if (Array.isArray(replacement)) {
                replacement.unshift(this.template);
                return this.indent + util.format.apply(util, replacement);
            } else {
                return this.indent + util.format(this.template, replacement);
            }
        }

        if (this.config.resolvePaths) {
            var replacementPath = path.resolve(this.file.cwd, replacement);
            replacement = path.relative(path.dirname(this.file.path), replacementPath);
            replacement = slash(replacement);
        }

        var ext = replacement.split('.').pop().toLowerCase();

        //add build version or timestamp support
        //some file like main.js?ts=123124
        //some file like main.js?sha1=0a9d
        ext = ext.split('?')[0].toLowerCase();

        if (ext === 'js') {
            return util.format('%s<script src="%s"></script>', this.indent, replacement);
        } else if (ext === 'css') {
            return util.format('%s<link rel="stylesheet" href="%s">', this.indent, replacement);
        }
        return this.indent + replacement;
    }.bind(this));
};

Block.prototype.compile = function (tasks) {
    var task = tasks[this.taskName];

    if (task) {
        this.replacements = task.src;
        this.template = task.tpl;
        this.uniqueExts = task.uni;
        this.srcIsNull = task.srcIsNull;
    }

    var buildResult = this.build();

    if (this.config.keepBlockTags) {
        buildResult.unshift(this.indent + this.beginTag);
        buildResult.push(this.indent + this.endTag);
    }

    buildResult.unshift(null);
    buildResult.push(null);

    return buildResult.join(this.linefeed);
};

module.exports = Block;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var when = require('when');
var nodefn = require('when/node');
var Serialport = require('browser-serialport');

function getFallbackType(){
  //TODO eventually will be used to select a board type when one isn't detected.
  return 'bs2';
}

function generateUniqueName(device){
  return device.type + '-' + device.path;
}

function addBoard(type, Board){
  this._boards[type] = Board;
}

function removeBoard(type){
  delete this._boards[type];
}

function listPorts(options){
  var reject = _.get(options, 'reject') || [];
  var predicate = reject;
  if(Array.isArray(reject)){
    predicate = function(port){
      return _.some(reject, function(entry){
        if(typeof entry === 'string'){
          return port.comName === entry;
        }
        return entry.test(port.comName);
      });
    };
  }
  return nodefn.call(Serialport.list)
    .then(function(portList){
      return _.reject(portList, predicate);
    });
}

function getBoard(options){
  var uniqueName = generateUniqueName(options);
  var device = this._devices[uniqueName];
  if(!device){
    var Board = this._boards[options.type];
    device = new Board(options.board);
    this._devices[uniqueName] = device;
  }
  return device;
}

function generateEmptyPortlist(portList){
  var type = getFallbackType();
  return _.map(portList, function(port){
    return {
      name: null,
      path: port,
      type: type,
      board: {
        path: port
      }
    };
  });
}

function scanBoards(options){
  var self = this;
  var opts = options || {};
  var targetBoards, targetTypes;
  if(opts.type){
    targetBoards = [this._boards[opts.type]];
    targetTypes = [opts.type];
  }else{
    targetBoards = _.values(this._boards);
    targetTypes = _.keys(this._boards);
  }

  return this.releaseAllBoards()
    .then(function(){
      self._devices = [];
      return self.listPorts(options);
    })
    .then(function(ports){
      var portList = _.pluck(ports, 'comName');
      return when.reduce(targetBoards, function(boardList, board, ix){
        return board.search(portList)
          .then(function(newBoards){
            _.forEach(newBoards, function(boardInfo){
              boardInfo.type = targetTypes[ix];
            });
            return boardList.concat(newBoards);
          });
      }, [])
      .then(function(boards){
        var allPorts = generateEmptyPortlist(portList);
        var emptyPorts = _.reject(allPorts, function(ep){
          return _.find(boards, { path: ep.path });
        });
        return boards.concat(emptyPorts);
      });
  });
}

function getOpenBoards(){
  return _.filter(_.values(this._devices), function(device){
    return device.isOpen();
  });
}

function releaseAllBoards(){
  var closingDevices = _.map(_.values(this._devices), function(device){
    if(device.isOpen()){
      return device.close();
    }
  });

  return when.settle(closingDevices);
}

module.exports = {
  addBoard: addBoard,
  releaseAllBoards: releaseAllBoards,
  getBoard: getBoard,
  getOpenBoards: getOpenBoards,
  listPorts: listPorts,
  removeBoard: removeBoard,
  scanBoards: scanBoards
};
<commit_msg>Cleanup getOpenBoards and releaseAllBoards<commit_after>'use strict';

var _ = require('lodash');
var when = require('when');
var nodefn = require('when/node');
var Serialport = require('browser-serialport');

function getFallbackType(){
  //TODO eventually will be used to select a board type when one isn't detected.
  return 'bs2';
}

function generateUniqueName(device){
  return device.type + '-' + device.path;
}

function addBoard(type, Board){
  this._boards[type] = Board;
}

function removeBoard(type){
  delete this._boards[type];
}

function listPorts(options){
  var reject = _.get(options, 'reject') || [];
  var predicate = reject;
  if(Array.isArray(reject)){
    predicate = function(port){
      return _.some(reject, function(entry){
        if(typeof entry === 'string'){
          return port.comName === entry;
        }
        return entry.test(port.comName);
      });
    };
  }
  return nodefn.call(Serialport.list)
    .then(function(portList){
      return _.reject(portList, predicate);
    });
}

function getBoard(options){
  var uniqueName = generateUniqueName(options);
  var device = this._devices[uniqueName];
  if(!device){
    var Board = this._boards[options.type];
    device = new Board(options.board);
    this._devices[uniqueName] = device;
  }
  return device;
}

function generateEmptyPortlist(portList){
  var type = getFallbackType();
  return _.map(portList, function(port){
    return {
      name: null,
      path: port,
      type: type,
      board: {
        path: port
      }
    };
  });
}

function scanBoards(options){
  var self = this;
  var opts = options || {};
  var targetBoards, targetTypes;
  if(opts.type){
    targetBoards = [this._boards[opts.type]];
    targetTypes = [opts.type];
  }else{
    targetBoards = _.values(this._boards);
    targetTypes = _.keys(this._boards);
  }

  return this.releaseAllBoards()
    .then(function(){
      self._devices = [];
      return self.listPorts(options);
    })
    .then(function(ports){
      var portList = _.pluck(ports, 'comName');
      return when.reduce(targetBoards, function(boardList, board, ix){
        return board.search(portList)
          .then(function(newBoards){
            _.forEach(newBoards, function(boardInfo){
              boardInfo.type = targetTypes[ix];
            });
            return boardList.concat(newBoards);
          });
      }, [])
      .then(function(boards){
        var allPorts = generateEmptyPortlist(portList);
        var emptyPorts = _.reject(allPorts, function(ep){
          return _.find(boards, { path: ep.path });
        });
        return boards.concat(emptyPorts);
      });
  });
}

function getOpenBoards(){
  return _.filter(this._devices, function(device){
    return device.isOpen();
  });
}

function releaseAllBoards(){
  var closingDevices = _.map(this.getOpenBoards(), function(device){
    return device.close();
  });

  return when.settle(closingDevices);
}

module.exports = {
  addBoard: addBoard,
  releaseAllBoards: releaseAllBoards,
  getBoard: getBoard,
  getOpenBoards: getOpenBoards,
  listPorts: listPorts,
  removeBoard: removeBoard,
  scanBoards: scanBoards
};
<|endoftext|>


<commit_before>const $ = require("jquery");
const boardSettings = require("./game-settings/board_settings");

const LoadingArea = require("./loading_area");
const ConveyorArea = require("./conveyor_area");

function Board(settings) {
  this.settings = settings || boardSettings();
  this.canvasHtml = this.settings.canvasHtml;
  this.loadingArea = new LoadingArea();
  this.conveyorArea = new ConveyorArea();

}
Board.prototype.start = function () {
  this.state = {};
  //now some of this will be later pulled out into initialize because
  //we want init and start to be 2 separate actions
  this.canvas = $(this.canvasHtml).appendTo("body");

  //init needs to happen once the page loads
  //start needs to start on a user action

  //draw out the basic areas based on their settings

  console.log("The Game has started");
  //main loop that will go and go until the game reaches an end
  requestAnimationFrame(function gameLoop() {
    this.updateState();
    this.render();
    requestAnimationFrame(gameLoop.bind(this));
  }.bind(this));
};

Board.prototype.updateState = function() {
  this.state.loadingArea = this.loadingArea.state;
  this.state.conveyorArea = this.loadingArea.state;
};

Board.prototype.render = function () {
  this.conveyorArea.render(this.canvas);
  this.loadingArea.render(this.canvas);
};

module.exports = Board;
<commit_msg>changed state to be in the main function<commit_after>const $ = require("jquery");
const boardSettings = require("./game-settings/board_settings");

const LoadingArea = require("./loading_area");
const ConveyorArea = require("./conveyor_area");

function Board(settings) {
  this.state = {};
  this.settings = settings || boardSettings();
  this.canvasHtml = this.settings.canvasHtml;
  this.loadingArea = new LoadingArea();
  this.conveyorArea = new ConveyorArea();

}
Board.prototype.start = function () {
  //now some of this will be later pulled out into initialize because
  //we want init and start to be 2 separate actions
  this.canvas = $(this.canvasHtml).appendTo("body");

  //init needs to happen once the page loads
  //start needs to start on a user action

  //draw out the basic areas based on their settings

  console.log("The Game has started");
  //main loop that will go and go until the game reaches an end
  requestAnimationFrame(function gameLoop() {
    this.updateState();
    this.render();
    requestAnimationFrame(gameLoop.bind(this));
  }.bind(this));
};

Board.prototype.updateState = function() {
  this.state.loadingArea = this.loadingArea.state;
  this.state.conveyorArea = this.loadingArea.state;
};

Board.prototype.render = function () {
  this.conveyorArea.render(this.canvas);
  this.loadingArea.render(this.canvas);
};

module.exports = Board;
<|endoftext|>


<commit_before>var events = require("events"),
    child = require("child_process"),
    util = require("util"),
    colors = require("colors"),
    Firmata = require("firmata").Board,
    Repl = require("../lib/repl.js"),
    board,
    Serial;

Serial = {
  detect: function( callback ) {
    var instance = this;

    this.info( "Board", "Connecting..." );

    child.exec( "ls /dev | grep -iE 'usb|acm'", function( err, stdout, stderr ) {
      var found,
          usb = stdout.slice( 0, -1 ).split("\n").filter(function( val ) {
            return (/tty/i).test( val );
          })[ 0 ];

      try {
        found = new Firmata( "/dev/" + usb, function() {
          // Execute "ready" callback
          callback.call( instance, err, "ready", found );
        });
      } catch ( error ) {
        err = error;
      }

      if ( err ) {
        err = err.message || err;
      }

      // Execute "connected" callback
      callback.call( instance, err, "connected", found );
    });
  }
};

// Board constructor: Firmata Board wrapper
function Board( opts ) {

  // Ensure opts is an object
  opts = opts || {};

  var keys = Object.keys( opts ),
      key;

  // Copy opts to constructor instance
  while ( keys.length ) {
    key = keys.shift();

    this[ key ] = opts[ key ];
  }

  // Easily track state of hardware
  this.ready = false;

  // Initialize instance property to reference firmata board
  this.firmata = null;

  // Identify for connected hardware cache
  if ( !this.id ) {
    this.id = Board.uid();
  }

  // If no debug flag, default to false
  if ( !("debug" in this) ) {
    this.debug = false;
  }

  // Create a Repl instance and store as
  // instance property of this firmata/board.
  // This will reduce the amount of boilerplate
  // code required to _always_ have a Repl
  // session available.
  this.repl = new Repl({
    board: this
  });

  // Used for testing only
  if ( this.mock ) {

    this.firmata = new Firmata( this.mock, function() {
      // Execute "connected" and "ready" callbacks
      this.emit( "connected", null );
      this.emit( "ready", null );
      this.ready = true;
    }.bind(this));
  } else {

    Serial.detect.call( this, function( err, type, board ) {
      if ( err ) {
        this.error( "Board", err );
      } else {
        // Assign found board to instance
        this.firmata = board;
        this.info( "Serialport", type );
        this.info( "Board", type );
      }

      if ( type === "connected" ) {
        process.on( "SIGINT", function() {
          this.warn( "Board", "Closing connection to board, serialport" );
          // On ^c, make sure we close the process after the
          // board and serialport are closed. Approx 100ms
          // TODO: this sucks, need better solution
          setTimeout(function() {
            process.exit();
          }.bind(this), 100);
        }.bind(this));
      }

      if ( type === "ready" ) {
        // Update instance `ready` flag
        this.ready = true;

        // Trigger the repl to start
        process.stdin.emit( "data", 1 );
      }

      // emit connect|ready event
      this.emit( type, err );
    });
  }

  // Cache instance to allow access from module constructors
  Board.cache.push( this );
}

// Inherit event api
util.inherits( Board, events.EventEmitter );

[ "pinMode", "analogWrite", "analogRead", "digitalWrite", "digitalRead" ].forEach(function( method ) {
  Board.prototype[ method ] = function( pin, arg ) {
    this.firmata[ method ]( pin, arg );
  };
});

Board.prototype.log = function( /* type, module, message [, long description] */ ) {
  var args = [].slice.call( arguments ),
      type = args.shift(),
      module = args.shift(),
      message = args.shift(),
      color = Board.prototype.log.types[ type ];

  if ( this.debug ) {
    console.log([
      // Timestamp
      String(+new Date()).grey,
      // Module, color matches type of log
      module.magenta,
      // Message
      message[ color ],
      // Miscellaneous args
      args.join(", ")
    ].join(" "));
  }
};

Board.prototype.log.types = {
  error: "red",
  fail: "orange",
  warn: "yellow",
  info: "cyan"
};

// Make shortcuts to all logging methods
Object.keys( Board.prototype.log.types ).forEach(function( type ) {
  Board.prototype[ type ] = function() {
    var args = [].slice.call( arguments );
    args.unshift( type );

    this.log.apply( this, args );
  };
});

// Static API

// Returns a reasonably unique id string
Board.uid = function() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(chr) {
    var rnd = Math.random() * 16 | 0;
    return (chr === "x" ? rnd : (rnd & 0x3 | 0x8)).toString(16);
  }).toUpperCase();
};

// Return hardware instance, based on param:
// @param {arg}
//   object, user specified
//   index, specified in cache
//   none, defaults to first in cache
//
// Used to reduce the amount of boilerplate
// code required in any given module or program, by
// giving the developer the option of omitting an
// explicit Board reference in a module
// constructor's options
Board.mount = function( arg ) {
  var index = typeof arg === "number" && arg,
      hardware;

  // board was explicitly provided
  if ( arg && arg.board ) {
    return arg.board;
  }

  // index specified, attempt to return
  // hardware instance. Return null if not
  // found or not available
  if ( index ) {
    hardware = Board.cache[ index ];
    return hardware && hardware || null;
  }

  // If no arg specified and hardware instances
  // exist in the cache
  if ( Board.cache.length ) {
    return Board.cache[ 0 ];
  }

  // No mountable hardware
  return null;
};

// Used when mode is ANALOG
// Board.analog = {
//   pins: {
//     "A0": 14,
//     "A1": 15,
//     "A2": 16,
//     "A3": 17,
//     "A4": 18,
//     "A5": 19
//   }
// };

Board.analog = {
  pins: {
    "A0": 0, //14,
    "A1": 1, //15,
    "A2": 2, //16,
    "A3": 3, //17,
    "A4": 4, //18,
    "A5": 5  //19
  }
};

// Used for SERVO or any PWM hardware
Board.pwm = {
  pins: {}
};

// Add all PWM pins
[ 3, 5, 6, 9, 10, 11 ].forEach(function( val ) {
  Board.pwm.pins[ val ] = true;
});

// Cached hardware
Board.cache = [];

module.exports = Board;
<commit_msg>Initial framework for Board prototype timer functions<commit_after>var events = require("events"),
    child = require("child_process"),
    util = require("util"),
    colors = require("colors"),
    Firmata = require("firmata").Board,
    Repl = require("../lib/repl.js"),
    board,
    Serial;

Serial = {
  detect: function( callback ) {
    var instance = this;

    this.info( "Board", "Connecting..." );

    child.exec( "ls /dev | grep -iE 'usb|acm'", function( err, stdout, stderr ) {
      var found,
          usb = stdout.slice( 0, -1 ).split("\n").filter(function( val ) {
            return (/tty/i).test( val );
          })[ 0 ];

      try {
        found = new Firmata( "/dev/" + usb, function() {
          // Execute "ready" callback
          callback.call( instance, err, "ready", found );
        });
      } catch ( error ) {
        err = error;
      }

      if ( err ) {
        err = err.message || err;
      }

      // Execute "connected" callback
      callback.call( instance, err, "connected", found );
    });
  }
};

// Board constructor: Firmata Board wrapper
function Board( opts ) {

  // Ensure opts is an object
  opts = opts || {};

  var keys = Object.keys( opts ),
      key;

  // Copy opts to constructor instance
  while ( keys.length ) {
    key = keys.shift();

    this[ key ] = opts[ key ];
  }

  // Easily track state of hardware
  this.ready = false;

  // Initialize instance property to reference firmata board
  this.firmata = null;

  // Identify for connected hardware cache
  if ( !this.id ) {
    this.id = Board.uid();
  }

  // If no debug flag, default to false
  if ( !("debug" in this) ) {
    this.debug = false;
  }

  // Create a Repl instance and store as
  // instance property of this firmata/board.
  // This will reduce the amount of boilerplate
  // code required to _always_ have a Repl
  // session available.
  this.repl = new Repl({
    board: this
  });

  // Used for testing only
  if ( this.mock ) {

    this.firmata = new Firmata( this.mock, function() {
      // Execute "connected" and "ready" callbacks
      this.emit( "connected", null );
      this.emit( "ready", null );
      this.ready = true;
    }.bind(this));
  } else {

    Serial.detect.call( this, function( err, type, board ) {
      if ( err ) {
        this.error( "Board", err );
      } else {
        // Assign found board to instance
        this.firmata = board;
        this.info( "Serialport", type );
        this.info( "Board", type );
      }

      if ( type === "connected" ) {
        process.on( "SIGINT", function() {
          this.warn( "Board", "Closing connection to board, serialport" );
          // On ^c, make sure we close the process after the
          // board and serialport are closed. Approx 100ms
          // TODO: this sucks, need better solution
          setTimeout(function() {
            process.exit();
          }.bind(this), 100);
        }.bind(this));
      }

      if ( type === "ready" ) {
        // Update instance `ready` flag
        this.ready = true;

        // Trigger the repl to start
        process.stdin.emit( "data", 1 );
      }

      // emit connect|ready event
      this.emit( type, err );
    });
  }

  // Cache instance to allow access from module constructors
  Board.cache.push( this );
}

// Inherit event api
util.inherits( Board, events.EventEmitter );

[ "pinMode", "analogWrite", "analogRead", "digitalWrite", "digitalRead" ].forEach(function( method ) {
  Board.prototype[ method ] = function( pin, arg ) {
    this.firmata[ method ]( pin, arg );
  };
});

Board.prototype.log = function( /* type, module, message [, long description] */ ) {
  var args = [].slice.call( arguments ),
      type = args.shift(),
      module = args.shift(),
      message = args.shift(),
      color = Board.prototype.log.types[ type ];

  if ( this.debug ) {
    console.log([
      // Timestamp
      String(+new Date()).grey,
      // Module, color matches type of log
      module.magenta,
      // Message
      message[ color ],
      // Miscellaneous args
      args.join(", ")
    ].join(" "));
  }
};

Board.prototype.log.types = {
  error: "red",
  fail: "orange",
  warn: "yellow",
  info: "cyan"
};

// Make shortcuts to all logging methods
Object.keys( Board.prototype.log.types ).forEach(function( type ) {
  Board.prototype[ type ] = function() {
    var args = [].slice.call( arguments );
    args.unshift( type );

    this.log.apply( this, args );
  };
});

// Aliasing.
// (temporary, while ironing out API details)
// The idea is to match existing hardware programming apis
// or simply find the words that are most intuitive.

// Eventually, there should be a queuing process
// for all new callbacks added

Board.prototype.wait = function( time, callback ) {
  return setTimeout( callback.bind(this), time );
};

Board.prototype.loop = function( time, callback ) {
  return setInterval( callback.bind(this), time );
};

// Board.prototype.timeout = Board.prototype.wait;
// Board.prototype.delay = Board.prototype.wait;
// Board.prototype.interval = Board.prototype.loop;

// Static API

// Returns a reasonably unique id string
Board.uid = function() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(chr) {
    var rnd = Math.random() * 16 | 0;
    return (chr === "x" ? rnd : (rnd & 0x3 | 0x8)).toString(16);
  }).toUpperCase();
};

// Return hardware instance, based on param:
// @param {arg}
//   object, user specified
//   index, specified in cache
//   none, defaults to first in cache
//
// Used to reduce the amount of boilerplate
// code required in any given module or program, by
// giving the developer the option of omitting an
// explicit Board reference in a module
// constructor's options
Board.mount = function( arg ) {
  var index = typeof arg === "number" && arg,
      hardware;

  // board was explicitly provided
  if ( arg && arg.board ) {
    return arg.board;
  }

  // index specified, attempt to return
  // hardware instance. Return null if not
  // found or not available
  if ( index ) {
    hardware = Board.cache[ index ];
    return hardware && hardware || null;
  }

  // If no arg specified and hardware instances
  // exist in the cache
  if ( Board.cache.length ) {
    return Board.cache[ 0 ];
  }

  // No mountable hardware
  return null;
};

// Used when mode is ANALOG
// Board.analog = {
//   pins: {
//     "A0": 14,
//     "A1": 15,
//     "A2": 16,
//     "A3": 17,
//     "A4": 18,
//     "A5": 19
//   }
// };

Board.analog = {
  pins: {
    "A0": 0, //14,
    "A1": 1, //15,
    "A2": 2, //16,
    "A3": 3, //17,
    "A4": 4, //18,
    "A5": 5  //19
  }
};

// Used for SERVO or any PWM hardware
Board.pwm = {
  pins: {}
};

// Add all PWM pins
[ 3, 5, 6, 9, 10, 11 ].forEach(function( val ) {
  Board.pwm.pins[ val ] = true;
});

// Cached hardware
Board.cache = [];

module.exports = Board;
<|endoftext|>


<commit_before>var _ = require('lodash'),
	async = require('async'),
	camelCase = require('camel-case'),
	exec = require('child_process').exec,
	fs = require('fs'),
	path = require('path'),
	prompt = require('prompt'),
	wrench = require('wrench');

var HOME = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE,
	CONFIG = '.bolts.json';

function bolts(opts, callback) {
	var defaults = {};
	callback = maybeCallback(arguments[arguments.length-1]);
	if (!opts || _.isFunction(opts)) {
		opts = {};
	}

	// config and defaults

	async.waterfall([

		// feed opts in waterfall
		function(cb) { return cb(null, opts, defaults); },

		// load default values
		loadDefaults,

		// load any relevant config files
		// loadConfig,

		// prompt for any missing required values
		promptForConfig,

		// write completed config to HOME
		// writeConfig,

		// generate the bootstrapped project
		generateProject,

		// git init
		gitInit

	], function(err, results) {
		if (err) { return callback(err); }
		return callback(null, results);
	});
}

module.exports = bolts;

function loadDefaults(opts, defaults, callback) {
	defaults = defaults || {};

	var funcs = [];
	['name','email'].forEach(function(type) {
		funcs.push(function(cb) {
			exec('git config --get user.' + type, function(err, stdout, stderr) {
				if (stderr || err) { return cb(); }
				defaults[type] = (stdout || '').trim();
				return cb();
			});
		});
	});

	async.parallel(funcs, function() {
		return callback(null, opts, defaults);
	});
}

/*
function loadConfig(opts, callback) {
	opts = opts || {};

	try {
		// explicit config file
		if (opts.config) {
			fs.readFile(opts.config, function(err, data) {
				return callback(null, JSON.parse(data));
			});

		// try to load local config file
		} else {
			var config = findConfig();
			return callback(null, config ? require(config) : null);
		}
	} catch (e) {
		return callback(e);
	}
}
*/

function promptForConfig(config, defaults, callback) {
	config = config || {};

	var title = prepTitle();

	console.log(title);
	console.log('┌──'.grey + ' Gimme some info and I\'ll create an npm-ready node.js module for you.');
	console.log('│'.grey);
	console.log('▼'.grey);

	prompt.message = '⚙'.green + '⚙'.white;
	prompt.delimiter = ' ';
	prompt.override = config;

	var schema = {
		properties: {
			project: {
				description: 'project name',
				required: true
			},
			description: {
				description: 'description',
				default: 'a node.js module',
				required: true
			},
			name: {
				description: 'author name',
				default: defaults.name,
				required: true
			},
			email: {
				description: 'author email',
				default: defaults.email,
				required: true
			},
			github: {
				description: 'github username',
				required: true
			}
		}
	};

	Object.keys(schema.properties).forEach(function(key) {
		schema.properties[key].description += ':';
	});

	prompt.start();
	prompt.get(schema, function (err, result) {
		if (err) { return callback(err); }

		config.projectCamelCase = camelCase(result.project);
		config.devDependencies = JSON.stringify({
			'grunt': '~0.4.5',
			'grunt-mocha-test': '~0.10.2',
			'grunt-contrib-jshint': '~0.10.0',
			'grunt-contrib-clean': '~0.5.0',
			'istanbul': '~0.2.10',
			'mocha': '~1.19.0',
			'should': '~3.3.1'
		}, null, '\t');
		return callback(null, _.extend(config, result));
	});
}

/*
function writeConfig(config, callback) {
	config = config || {};
	var configFile = path.join(HOME, CONFIG);
	fs.writeFile(configFile, JSON.stringify(config, null, 2), function(err) {
		return callback(err, config, configFile);
	});
}
*/

function generateProject(config, callback) {
	config = config || {};

	var dest = path.resolve(config.project);
	if (fs.existsSync(dest) && !config.force) {
		return callback('"' + config.project + '" already exists. Use --force to overwrite.');
	}
	//wrench.mkdirSyncRecursive(dest, 0755);

	// copy all files in
	wrench.copyDirSyncRecursive(path.join(__dirname, '..', 'src'), dest, {
		forceDelete: true
	});
	wrench.mkdirSyncRecursive(path.join(dest, 'node_modules'));

	// iterate through all files and update them with templates
	wrench.readdirSyncRecursive(dest).forEach(function(file) {
		var fullpath = path.join(dest, file);
		if (fs.statSync(fullpath).isFile()) {
			fs.writeFileSync(fullpath, _.template(fs.readFileSync(fullpath, 'utf8'), config));
		}
	});

	// rename source project files
	fs.renameSync(path.join(dest, 'lib', 'module.js'), path.join(dest, 'lib', config.project + '.js'));
	fs.renameSync(path.join(dest, 'test', 'module_test.js'), path.join(dest, 'test', config.project + '_test.js'));

function gitInit(opts, callback) {
	exec('cd "' + opts.project + '" && git init', function(err, stdout, stderr) {
		if (err) {
			console.error('git init failed: ' + err);
		}
		return callback(null, opts);
	});
}

// helpers
function findConfig() {
	var result = null,
		configs = [
			path.resolve(CONFIG),
			path.join(HOME, CONFIG)
		];

	// see if we have a config saved in either CWD or HOME
	configs.every(function(config) {
		if (fs.existsSync(config)) {
			result = config;
			return false;
		}
		return true;
	});

	return result;
}

function prepTitle() {
	var title = fs.readFileSync(path.join(__dirname, '..', 'assets', 'title.txt'), 'utf8'),
		newTitle = '';

	title.split('\n').forEach(function(line) {
		newTitle += '            ' + line + '\n';
	});

	return '\n' + newTitle.replace(/\$/g, '$'.red).replace(/([\\\/_|])/g, '$1'.grey).bold + '\n';
}

function maybeCallback(cb) {
	return _.isFunction(cb) ? cb : function(err) { if (err) { throw err; } };
}

(function logs(level, color) {
	if (!level) { return; }
	var _console = console[level];
	console[level] = function() {
		var args = Array.prototype.slice.call(arguments, 0);
		args[0] = _.isString(args[0]) ? args[0][color] : args[0];
		_console.apply(console, args);
	};
	return logs;
})
('error','red')
('warn','yellow')
('log','white')
('debug','cyan');
<commit_msg>refactor async params<commit_after>var _ = require('lodash'),
	async = require('async'),
	camelCase = require('camel-case'),
	exec = require('child_process').exec,
	fs = require('fs'),
	path = require('path'),
	prompt = require('prompt'),
	wrench = require('wrench');

var HOME = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE,
	CONFIG = '.bolts.json';

function bolts(opts, callback) {
	var defaults = {};
	callback = maybeCallback(arguments[arguments.length-1]);
	if (!opts || _.isFunction(opts)) {
		opts = {};
	}

	async.waterfall([

		// feed opts in waterfall
		function(cb) { return cb(null, opts, defaults); },

		// load default values
		loadDefaults,

		// load any relevant config files
		// loadConfig,

		// prompt for any missing required values
		promptForConfig,

		// write completed config to HOME
		// writeConfig,

		// generate the bootstrapped project
		generateProject,

		// git init
		gitInit

	], function(err, results) {
		if (err) { return callback(err); }
		return callback(null, results);
	});
}

module.exports = bolts;

function loadDefaults(opts, defaults, callback) {
	defaults = defaults || {};

	var funcs = [];
	['name','email'].forEach(function(type) {
		funcs.push(function(cb) {
			exec('git config --get user.' + type, function(err, stdout, stderr) {
				if (stderr || err) { return cb(); }
				defaults[type] = (stdout || '').trim();
				return cb();
			});
		});
	});

	async.parallel(funcs, function() {
		return callback(null, opts, defaults);
	});
}

/*
function loadConfig(opts, callback) {
	opts = opts || {};

	try {
		// explicit config file
		if (opts.config) {
			fs.readFile(opts.config, function(err, data) {
				return callback(null, JSON.parse(data));
			});

		// try to load local config file
		} else {
			var config = findConfig();
			return callback(null, config ? require(config) : null);
		}
	} catch (e) {
		return callback(e);
	}
}
*/

function promptForConfig(opts, defaults, callback) {
	opts = opts || {};

	var title = prepTitle();

	console.log(title);
	console.log('┌──'.grey + ' Gimme some info and I\'ll create an npm-ready node.js module for you.');
	console.log('│'.grey);
	console.log('▼'.grey);

	prompt.message = '⚙'.green + '⚙'.white;
	prompt.delimiter = ' ';
	prompt.override = opts;

	var schema = {
		properties: {
			project: {
				description: 'project name',
				required: true
			},
			description: {
				description: 'description',
				default: 'a node.js module',
				required: true
			},
			name: {
				description: 'author name',
				default: defaults.name,
				required: true
			},
			email: {
				description: 'author email',
				default: defaults.email,
				required: true
			},
			github: {
				description: 'github username',
				required: true
			}
		}
	};

	Object.keys(schema.properties).forEach(function(key) {
		schema.properties[key].description += ':';
	});

	prompt.start();
	prompt.get(schema, function (err, result) {
		if (err) { return callback(err); }

		opts.projectCamelCase = camelCase(result.project);
		opts.devDependencies = JSON.stringify({
			'grunt': '~0.4.5',
			'grunt-mocha-test': '~0.10.2',
			'grunt-contrib-jshint': '~0.10.0',
			'grunt-contrib-clean': '~0.5.0',
			'istanbul': '~0.2.10',
			'mocha': '~1.19.0',
			'should': '~3.3.1'
		}, null, '\t');
		return callback(null, _.extend(opts, result));
	});
}

/*
function writeConfig(config, callback) {
	config = config || {};
	var configFile = path.join(HOME, CONFIG);
	fs.writeFile(configFile, JSON.stringify(config, null, 2), function(err) {
		return callback(err, config, configFile);
	});
}
*/

function generateProject(opts, callback) {
	opts = opts || {};

	var dest = path.resolve(opts.project);
	if (fs.existsSync(dest) && !opts.force) {
		return callback('"' + opts.project + '" already exists. Use --force to overwrite.');
	}

	// copy all files in
	wrench.copyDirSyncRecursive(path.join(__dirname, '..', 'src'), dest, {
		forceDelete: true
	});
	wrench.mkdirSyncRecursive(path.join(dest, 'node_modules'));

	// iterate through all files and update them with templates
	wrench.readdirSyncRecursive(dest).forEach(function(file) {
		var fullpath = path.join(dest, file);
		if (fs.statSync(fullpath).isFile()) {
			fs.writeFileSync(fullpath, _.template(fs.readFileSync(fullpath, 'utf8'), opts));
		}
	});

	// rename source project files
	fs.renameSync(path.join(dest, 'lib', 'module.js'), path.join(dest, 'lib', opts.project + '.js'));
	fs.renameSync(path.join(dest, 'test', 'module_test.js'), path.join(dest, 'test', opts.project + '_test.js'));

	return callback(null, opts);
}

function gitInit(opts, callback) {
	exec('cd "' + opts.project + '" && git init', function(err, stdout, stderr) {
		if (err) {
			console.error('git init failed: ' + err);
		}
		return callback(null, opts);
	});
}

// helpers
function findConfig() {
	var result = null,
		configs = [
			path.resolve(CONFIG),
			path.join(HOME, CONFIG)
		];

	// see if we have a config saved in either CWD or HOME
	configs.every(function(config) {
		if (fs.existsSync(config)) {
			result = config;
			return false;
		}
		return true;
	});

	return result;
}

function prepTitle() {
	var title = fs.readFileSync(path.join(__dirname, '..', 'assets', 'title.txt'), 'utf8'),
		newTitle = '';

	title.split('\n').forEach(function(line) {
		newTitle += '            ' + line + '\n';
	});

	return '\n' + newTitle.replace(/\$/g, '$'.red).replace(/([\\\/_|])/g, '$1'.grey).bold + '\n';
}

function maybeCallback(cb) {
	return _.isFunction(cb) ? cb : function(err) { if (err) { throw err; } };
}

(function logs(level, color) {
	if (!level) { return; }
	var _console = console[level];
	console[level] = function() {
		var args = Array.prototype.slice.call(arguments, 0);
		args[0] = _.isString(args[0]) ? args[0][color] : args[0];
		_console.apply(console, args);
	};
	return logs;
})
('error','red')
('warn','yellow')
('log','white')
('debug','cyan');
<|endoftext|>