<commit_before>'use strict';

var through = require('through2').obj;
var path = require('path');
var istanbul = require('istanbul');
var gutil = require('gulp-util');
var _ = require('lodash');
var Report = istanbul.Report;
var Collector = istanbul.Collector;
var PluginError = gutil.PluginError;
var checker = require('istanbul-threshold-checker');

var PLUGIN_NAME = 'gulp-istanbul';
var COVERAGE_VARIABLE = '$$cov_' + new Date().getTime() + '$$';

var plugin = module.exports = function (opts) {
  opts = opts || {};
  _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE,
    instrumenter: istanbul.Instrumenter
  });
  opts.includeUntested = opts.includeUntested === true;

  var instrumenter = new opts.instrumenter(opts);

  return through(function (file, enc, cb) {
    cb = _.once(cb);
    if (!(file.contents instanceof Buffer)) {
      return cb(new PluginError(PLUGIN_NAME, 'streams not supported'));
    }

    instrumenter.instrument(file.contents.toString(), file.path, function (err, code) {
      if (err) {
        return cb(new PluginError(
          PLUGIN_NAME,
          'Unable to parse ' + file.path + '\n\n' + err.message + '\n'
        ));
      }

      file.contents = new Buffer(code);

      // Parse the blank coverage object from the instrumented file and save it
      // to the global coverage variable to enable reporting on non-required
      // files, a workaround for
      // https://github.com/gotwarlost/istanbul/issues/112
      if (opts.includeUntested) {
        var instrumentedSrc = file.contents.toString();
        var covStubRE = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g;
        var covStubMatch = covStubRE.exec(instrumentedSrc);
        if (covStubMatch !== null) {
          var covStub = JSON.parse(covStubMatch[0]);
          global[opts.coverageVariable] = global[opts.coverageVariable] || {};
          global[opts.coverageVariable][path.resolve(file.path)] = covStub;
        }
      }

      return cb(err, file);
    });
  });
};

plugin.hookRequire = function (options) {
  var fileMap = {};

  istanbul.hook.unhookRequire();
  istanbul.hook.hookRequire(function (path) {
    return !!fileMap[path];
  }, function (code, path) {
    return fileMap[path];
  }, options);

  return through(function (file, enc, cb) {
    // If the file is already required, delete it from the cache otherwise the covered
    // version will be ignored.
    delete require.cache[path.resolve(file.path)];
    fileMap[file.path] = file.contents.toString();
    return cb();
  });
};

plugin.summarizeCoverage = function (opts) {
  opts = opts || {};
  if (!opts.coverageVariable) opts.coverageVariable = COVERAGE_VARIABLE;

  if (!global[opts.coverageVariable]) throw new Error('no coverage data found, run tests before calling `summarizeCoverage`');

  var collector = new Collector();
  collector.add(global[opts.coverageVariable]);
  return istanbul.utils.summarizeCoverage(collector.getFinalCoverage());
};

plugin.writeReports = function (opts) {
  if (typeof opts === 'string') opts = { dir: opts };
  opts = opts || {};

  var defaultDir = path.join(process.cwd(), 'coverage');
  opts = _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE,
    dir: defaultDir,
    reporters: [ 'lcov', 'json', 'text', 'text-summary' ],
    reportOpts: { dir: opts.dir || defaultDir }
  });

  var reporters = opts.reporters.map(function(reporter) {
    if (reporter.TYPE) Report.register(reporter);
    return reporter.TYPE || reporter;
  });

  var invalid = _.difference(reporters, Report.getReportList());
  if (invalid.length) {
    // throw before we start -- fail fast
    throw new PluginError(PLUGIN_NAME, 'Invalid reporters: ' + invalid.join(', '));
  }

  reporters = reporters.map(function (r) {
    var reportOpts = opts.reportOpts[r] || opts.reportOpts;
    return Report.create(r, _.clone(reportOpts));
  });

  var cover = through();

  cover.on('end', function () {
    var collector = new Collector();

    // Revert to an object if there are no matching source files.
    collector.add(global[opts.coverageVariable] || {});

    reporters.forEach(function (report) {
      report.writeReport(collector, true);
    });
  }).resume();

  return cover;
};

plugin.enforceThresholds = function (opts) {
  opts = opts || {};
  opts = _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE
  });

  var cover = through();

  cover.on('end', function () {
    var collector = new Collector();

    // Revert to an object if there are no macthing source files.
    collector.add(global[opts.coverageVariable] || {});

    var results = checker.checkFailures(opts.thresholds, collector.getFinalCoverage());
    var criteria = function(type) {
      return (type.global && type.global.failed) || (type.each && type.each.failed);
    };

    if (_.any(results, criteria)) {
      this.emit('error', new PluginError({
        plugin: PLUGIN_NAME,
        message: 'Coverage failed'
      }));
    }

  }).resume();

  return cover;
};
<commit_msg>Put the require of the checker before requiring istanbul.<commit_after>'use strict';

var through = require('through2').obj;
var path = require('path');
var checker = require('istanbul-threshold-checker');
var istanbul = require('istanbul');
var gutil = require('gulp-util');
var _ = require('lodash');
var Report = istanbul.Report;
var Collector = istanbul.Collector;
var PluginError = gutil.PluginError;

var PLUGIN_NAME = 'gulp-istanbul';
var COVERAGE_VARIABLE = '$$cov_' + new Date().getTime() + '$$';

var plugin = module.exports = function (opts) {
  opts = opts || {};
  _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE,
    instrumenter: istanbul.Instrumenter
  });
  opts.includeUntested = opts.includeUntested === true;

  var instrumenter = new opts.instrumenter(opts);

  return through(function (file, enc, cb) {
    cb = _.once(cb);
    if (!(file.contents instanceof Buffer)) {
      return cb(new PluginError(PLUGIN_NAME, 'streams not supported'));
    }

    instrumenter.instrument(file.contents.toString(), file.path, function (err, code) {
      if (err) {
        return cb(new PluginError(
          PLUGIN_NAME,
          'Unable to parse ' + file.path + '\n\n' + err.message + '\n'
        ));
      }

      file.contents = new Buffer(code);

      // Parse the blank coverage object from the instrumented file and save it
      // to the global coverage variable to enable reporting on non-required
      // files, a workaround for
      // https://github.com/gotwarlost/istanbul/issues/112
      if (opts.includeUntested) {
        var instrumentedSrc = file.contents.toString();
        var covStubRE = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g;
        var covStubMatch = covStubRE.exec(instrumentedSrc);
        if (covStubMatch !== null) {
          var covStub = JSON.parse(covStubMatch[0]);
          global[opts.coverageVariable] = global[opts.coverageVariable] || {};
          global[opts.coverageVariable][path.resolve(file.path)] = covStub;
        }
      }

      return cb(err, file);
    });
  });
};

plugin.hookRequire = function (options) {
  var fileMap = {};

  istanbul.hook.unhookRequire();
  istanbul.hook.hookRequire(function (path) {
    return !!fileMap[path];
  }, function (code, path) {
    return fileMap[path];
  }, options);

  return through(function (file, enc, cb) {
    // If the file is already required, delete it from the cache otherwise the covered
    // version will be ignored.
    delete require.cache[path.resolve(file.path)];
    fileMap[file.path] = file.contents.toString();
    return cb();
  });
};

plugin.summarizeCoverage = function (opts) {
  opts = opts || {};
  if (!opts.coverageVariable) opts.coverageVariable = COVERAGE_VARIABLE;

  if (!global[opts.coverageVariable]) throw new Error('no coverage data found, run tests before calling `summarizeCoverage`');

  var collector = new Collector();
  collector.add(global[opts.coverageVariable]);
  return istanbul.utils.summarizeCoverage(collector.getFinalCoverage());
};

plugin.writeReports = function (opts) {
  if (typeof opts === 'string') opts = { dir: opts };
  opts = opts || {};

  var defaultDir = path.join(process.cwd(), 'coverage');
  opts = _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE,
    dir: defaultDir,
    reporters: [ 'lcov', 'json', 'text', 'text-summary' ],
    reportOpts: { dir: opts.dir || defaultDir }
  });

  var reporters = opts.reporters.map(function(reporter) {
    if (reporter.TYPE) Report.register(reporter);
    return reporter.TYPE || reporter;
  });

  var invalid = _.difference(reporters, Report.getReportList());
  if (invalid.length) {
    // throw before we start -- fail fast
    throw new PluginError(PLUGIN_NAME, 'Invalid reporters: ' + invalid.join(', '));
  }

  reporters = reporters.map(function (r) {
    var reportOpts = opts.reportOpts[r] || opts.reportOpts;
    return Report.create(r, _.clone(reportOpts));
  });

  var cover = through();

  cover.on('end', function () {
    var collector = new Collector();

    // Revert to an object if there are no matching source files.
    collector.add(global[opts.coverageVariable] || {});

    reporters.forEach(function (report) {
      report.writeReport(collector, true);
    });
  }).resume();

  return cover;
};

plugin.enforceThresholds = function (opts) {
  opts = opts || {};
  opts = _.defaults(opts, {
    coverageVariable: COVERAGE_VARIABLE
  });

  var cover = through();

  cover.on('end', function () {
    var collector = new Collector();

    // Revert to an object if there are no macthing source files.
    collector.add(global[opts.coverageVariable] || {});

    var results = checker.checkFailures(opts.thresholds, collector.getFinalCoverage());
    var criteria = function(type) {
      return (type.global && type.global.failed) || (type.each && type.each.failed);
    };

    if (_.any(results, criteria)) {
      this.emit('error', new PluginError({
        plugin: PLUGIN_NAME,
        message: 'Coverage failed'
      }));
    }

  }).resume();

  return cover;
};
<|endoftext|>


<commit_before>var parse = require('acorn').parse;

module.exports = function (src) {
    // If src is a Buffer, esprima will just stringify it, so we beat them to
    // the punch. This avoids the problem where we're using esprima's range
    // indexes -- which are meant for a UTF-16 string -- in a buffer that
    // contains UTF-8 encoded text.
    if (typeof src !== 'string') {
        src = String(src);
    }

    var ast = parse(src, { range: true });

    ast.body = ast.body.filter(function(node) {
        return node.type !== 'EmptyStatement';
    });

    if (ast.body.length !== 1) return;
    if (ast.body[0].type !== 'ExpressionStatement') return;
    if (ast.body[0].expression.type === 'UnaryExpression') {
        var body = ast.body[0].expression.argument;
    } else if (ast.body[0].expression.type === 'AssignmentExpression') {
        var body = ast.body[0].expression.right;
    } else {
        var body = ast.body[0].expression;
    }

    if (body.type !== 'CallExpression') return;

    var args = body.arguments;
    if (args.length === 1) args = extractStandalone(args) || args;
    if (args.length !== 3) return;

    if (args[0].type !== 'ObjectExpression') return;
    if (args[1].type !== 'ObjectExpression') return;
    if (args[2].type !== 'ArrayExpression') return;

    var files = args[0].properties;
    var cache = args[1];
    var entries = args[2].elements.map(function (e) {
        return e.value
    });

    return files.map(function (file) {
        var body = file.value.elements[0].body.body;
        var start, end;
        if (body.length === 0) {
            start = body.start || 0;
            end = body.end || 0;
        }
        else {
            start = body[0].start;
            end = body[body.length-1].end;
        }

        var depProps = file.value.elements[1].properties;
        var deps = depProps.reduce(function (acc, dep) {
            var key = dep.key.type === 'Literal'
                ? dep.key.value
                : dep.key.name;
            acc[key] = dep.value.value;
            return acc;
        }, {});
        var row = {
            id: file.key.value,
            source: src.slice(start, end),
            deps: deps
        };
        if (entries.indexOf(row.id) >= 0) row.entry = true;
        return row;
    });
};

function extractStandalone (args) {
    if (args[0].type !== 'FunctionExpression') return;
    if (args[0].body.length < 2) return;
    if (args[0].body.body.length < 2) return;

    args = args[0].body.body[1].argument;
    if (args.type !== 'CallExpression') return;
    if (args.callee.type !== 'CallExpression') return;

    return args.callee.arguments;
};
<commit_msg>fix require()<commit_after>var parse = require('acorn-node').parse;

module.exports = function (src) {
    // If src is a Buffer, esprima will just stringify it, so we beat them to
    // the punch. This avoids the problem where we're using esprima's range
    // indexes -- which are meant for a UTF-16 string -- in a buffer that
    // contains UTF-8 encoded text.
    if (typeof src !== 'string') {
        src = String(src);
    }

    var ast = parse(src, { range: true });

    ast.body = ast.body.filter(function(node) {
        return node.type !== 'EmptyStatement';
    });

    if (ast.body.length !== 1) return;
    if (ast.body[0].type !== 'ExpressionStatement') return;
    if (ast.body[0].expression.type === 'UnaryExpression') {
        var body = ast.body[0].expression.argument;
    } else if (ast.body[0].expression.type === 'AssignmentExpression') {
        var body = ast.body[0].expression.right;
    } else {
        var body = ast.body[0].expression;
    }

    if (body.type !== 'CallExpression') return;

    var args = body.arguments;
    if (args.length === 1) args = extractStandalone(args) || args;
    if (args.length !== 3) return;

    if (args[0].type !== 'ObjectExpression') return;
    if (args[1].type !== 'ObjectExpression') return;
    if (args[2].type !== 'ArrayExpression') return;

    var files = args[0].properties;
    var cache = args[1];
    var entries = args[2].elements.map(function (e) {
        return e.value
    });

    return files.map(function (file) {
        var body = file.value.elements[0].body.body;
        var start, end;
        if (body.length === 0) {
            start = body.start || 0;
            end = body.end || 0;
        }
        else {
            start = body[0].start;
            end = body[body.length-1].end;
        }

        var depProps = file.value.elements[1].properties;
        var deps = depProps.reduce(function (acc, dep) {
            var key = dep.key.type === 'Literal'
                ? dep.key.value
                : dep.key.name;
            acc[key] = dep.value.value;
            return acc;
        }, {});
        var row = {
            id: file.key.value,
            source: src.slice(start, end),
            deps: deps
        };
        if (entries.indexOf(row.id) >= 0) row.entry = true;
        return row;
    });
};

function extractStandalone (args) {
    if (args[0].type !== 'FunctionExpression') return;
    if (args[0].body.length < 2) return;
    if (args[0].body.body.length < 2) return;

    args = args[0].body.body[1].argument;
    if (args.type !== 'CallExpression') return;
    if (args.callee.type !== 'CallExpression') return;

    return args.callee.arguments;
};
<|endoftext|>


<commit_before>var assert = require('assert');
var Optical = {};
Optical.OPTIMISED = 1;
Optical.NOT_OPTIMISED = 2;
Optical.ALWAYS_OPTIMISED = 3;
Optical.NEVER_OPTIMSISED = 4;
Optical.MAY_BE_OPTIMISED = 6;

function testOptimisationStatus(fn, args, thisArg) {
	var n =  10000000;
	while (n >= 0) {
		n--;
		fn.apply(thisArg, args);
	}

	%OptimizeFunctionOnNextCall(fn);
	fn.apply(thisArg, args);

	return %GetOptimizationStatus(fn);
}

function printOptimisationStatus(functionName, status) {
    switch(status) {
		case Optical.OPTIMISED: console.log("Function ", functionName, " is optimized"); break;
        case Optical.NOT_OPTIMISED: console.log("Function ", functionName, " is not optimized"); break;
        case Optical.ALWAYS_OPTIMISED: console.log("Function  ", functionName, " is always optimized"); break;
        case Optical.NEVER_OPTIMISED: console.log("Function  ", functionName, " is never optimized"); break;

        case Optical.MAY_BE_OPTIMISED: console.log("Function  ", functionName, " will probably deoptimize"); break;
    }
}

module.exports = function(func, args, thisArg) {
	printOptimisationStatus(func, testOptimisationStatus(func, args, thisArg));
};

module.exports.assertOptimized = function(func, args, thisArg) {
	var optimisationStatus = testOptimisationStatus(func, args, thisArg);
	assert(optimisationStatus === Optical.OPTIMISED || optimisationStatus === Optical.ALWAYS_OPTIMISED);
};
<commit_msg>Indent<commit_after>var assert = require('assert');
var Optical = {};
Optical.OPTIMISED = 1;
Optical.NOT_OPTIMISED = 2;
Optical.ALWAYS_OPTIMISED = 3;
Optical.NEVER_OPTIMSISED = 4;
Optical.MAY_BE_OPTIMISED = 6;

function testOptimisationStatus(fn, args, thisArg) {
	var n =  10000000;
	while (n >= 0) {
		n--;
		fn.apply(thisArg, args);
	}

	%OptimizeFunctionOnNextCall(fn);
	fn.apply(thisArg, args);

	return %GetOptimizationStatus(fn);
}

function printOptimisationStatus(functionName, status) {
    switch(status) {
	case Optical.OPTIMISED: console.log("Function ", functionName, " is optimized"); break;
        case Optical.NOT_OPTIMISED: console.log("Function ", functionName, " is not optimized"); break;
        case Optical.ALWAYS_OPTIMISED: console.log("Function  ", functionName, " is always optimized"); break;
        case Optical.NEVER_OPTIMISED: console.log("Function  ", functionName, " is never optimized"); break;

        case Optical.MAY_BE_OPTIMISED: console.log("Function  ", functionName, " will probably deoptimize"); break;
    }
}

module.exports = function(func, args, thisArg) {
	printOptimisationStatus(func, testOptimisationStatus(func, args, thisArg));
};

module.exports.assertOptimized = function(func, args, thisArg) {
	var optimisationStatus = testOptimisationStatus(func, args, thisArg);
	assert(optimisationStatus === Optical.OPTIMISED || optimisationStatus === Optical.ALWAYS_OPTIMISED);
};
<|endoftext|>


<commit_before>var through2 = require('through2'),
    mime = require('mime'),
    css = require('css'),
    htmlparser2 = require('htmlparser2'),
    gutil = require('gulp-util'),
    path = require('path'),
    _ = require('lodash');

var PLUGIN_NAME = 'gulp-unused-images';

function unusedImages() {
    function addUsed(imageUrl) {
        if (!imageUrl.match(/(data|http|https):/)) {
            usedImageNames.push(path.basename(imageUrl));
        }
    }

    var imageNames = [];
    var usedImageNames = [];
    var ngUsedImages = [];

    var htmlParser = new htmlparser2.Parser({
        onopentag: function onopentag(name, attribs) {
            if (name === 'img') {
                if (attribs.src) {
                    addUsed(attribs.src);
                }
                if (attribs['ng-src']) {
                    ngUsedImages.push(attribs['ng-src']);
                }
            }
            else if (name === 'link' && attribs.href) {
                addUsed(attribs.href);
            }
            else if (name === 'meta' && attribs.content) {
                addUsed(attribs.content);
            }
        }
    });

    var transform = through2.obj(function (chunk, enc, callback) {
        var self = this;

        if (chunk.isNull()) {
            self.push(chunk);
            return callback();
        }

        if (chunk.isStream()) {
            return callback(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
        }

        if (mime.lookup(chunk.path).match(/image\//)) {
            imageNames.push(path.basename(chunk.path));
            return callback();
        }

        try {
            var ast = css.parse(String(chunk.contents));
            ast.stylesheet.rules.forEach(function (rule) {
                if (rule.type !== 'rule') {
                    return;
                }

                rule.declarations.forEach(function (declaration) {
                    var match = declaration.value.match(/url\(("|'|)(.+?)\1\)/);
                    if (match) {
                        addUsed(match[2]);
                    }
                });
            });
        }
        catch (e) {
            htmlParser.write(String(chunk.contents));
        }

        self.push(chunk);
        callback();
    });

    transform.on('finish', function () {
        var unused = _.difference(imageNames, usedImageNames);
        if (unused.length) {
            this.emit('error', new Error('Unused images: ' + unused.join(', ') + '\nng-src: ' + ngUsedImages.join(', ')));
        }
    });

    return transform;
}

module.exports = unusedImages;
<commit_msg>couple of needed comments<commit_after>var through2 = require('through2'),
    mime = require('mime'),
    css = require('css'),
    htmlparser2 = require('htmlparser2'),
    gutil = require('gulp-util'),
    path = require('path'),
    _ = require('lodash');

var PLUGIN_NAME = 'gulp-unused-images';

function unusedImages() {
    function addUsed(imageUrl) {
        if (!imageUrl.match(/(data|http|https):/)) {
            usedImageNames.push(path.basename(imageUrl));
        }
    }

    var imageNames = [];
    var usedImageNames = [];
    var ngUsedImages = [];

    var htmlParser = new htmlparser2.Parser({
        onopentag: function onopentag(name, attribs) {
            if (name === 'img') {
                if (attribs.src) {
                    addUsed(attribs.src);
                }
                if (attribs['ng-src']) {
                    ngUsedImages.push(attribs['ng-src']);
                }
            }
			// eg shortcut icon apple-touch-icon, it doesnt matter if we add extras that are not images
            else if (name === 'link' && attribs.href) {
                addUsed(attribs.href);
            }
			// eg msapplication-xxx
            else if (name === 'meta' && attribs.content) {
                addUsed(attribs.content);
            }
        }
    });

    var transform = through2.obj(function (chunk, enc, callback) {
        var self = this;

        if (chunk.isNull()) {
            self.push(chunk);
            return callback();
        }

        if (chunk.isStream()) {
            return callback(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
        }

        if (mime.lookup(chunk.path).match(/image\//)) {
            imageNames.push(path.basename(chunk.path));
            return callback();
        }

        try {
            var ast = css.parse(String(chunk.contents));
            ast.stylesheet.rules.forEach(function (rule) {
                if (rule.type !== 'rule') {
                    return;
                }

                rule.declarations.forEach(function (declaration) {
                    var match = declaration.value.match(/url\(("|'|)(.+?)\1\)/);
                    if (match) {
                        addUsed(match[2]);
                    }
                });
            });
        }
        catch (e) {
            htmlParser.write(String(chunk.contents));
        }

        self.push(chunk);
        callback();
    });

    transform.on('finish', function () {
        var unused = _.difference(imageNames, usedImageNames);
        if (unused.length) {
            this.emit('error', new Error('Unused images: ' + unused.join(', ') + '\nng-src: ' + ngUsedImages.join(', ')));
        }
    });

    return transform;
}

module.exports = unusedImages;
<|endoftext|>


<commit_before>var util = require('util');
var EventEmitter = require('events').EventEmitter;
var nmea = require('nmea');
var Packetizer = require('./lib/packetizer');

var DEBUG = true;  //  Set to true for debug console logs

var GPS = function (hardware, callback) {
  /*
  Constructor

  Args
    hardware
      The Tessel port to use
    callback
      Callback function
  */
  var self = this;
  //set this.types for each type
  //type: fix, nav-info, 2waypoint, autopilot-b
  this.hardware = hardware;
  this.onOff = this.hardware.gpio(3);
  this.powerState = 'off';
  this.timeoutDuration = 10*1000;
  this.format = 'deg-min-dec';
  //  A collection of attributes and callback functions. See set/removeCallbacks.
  this.callbacks = {};

  //  Turn the module on
  self.initialPowerSequence(function (err) {
    if (!err) {
      //  Once we are on, emit the connected event
      self.beginDecoding(function () {

        setImmediate(function () {
          self.emit('ready');
          if (callback) {
            callback();
          }
        });
      });
    } else {
      setImmediate(function () {
        self.emit('error', err);
      });
    }
  });
};

util.inherits(GPS, EventEmitter);

GPS.prototype.initialPowerSequence = function (callback) {
  /*
  Turn on and establish contact with the A2235-H GPS module

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  //  Tell Tessel to start UART at GPS baud rate
  this.uart = this.hardware.UART({baudrate : 115200});

  var noReceiveTimeout;

  function waitForData () {
    //  Remove this listener when we hear something (anything) from the GPS
    self.uart.removeListener('data', waitForData);

    clearTimeout(noReceiveTimeout);

    //  And note that we are on
    self.powerState = 'on';

    //  Tell the A2235-H that we want it to give us NMEA strings over UART
    self._switchToNMEA9800(callback);
  }

  function noDataRecieved () {
    //  Remove the listener for any data
    self.uart.removeListener('data', waitForData);
    //  Clear the timeout
    clearTimeout(noReceiveTimeout);
    //  Call the callback
    if (callback) {
      callback(new Error('Unable to connect to module...'));
    }
  }

  /*
  Wait for a second to see if we get data. If we do, call callback;
  If we don't, toggle power and set timeout again
  If we still don't get it, something bigger is wrong
  */

  //  This event listener will wait for valid data to note that we are on
  self.uart.once('data', function (data) {
    waitForData(data);
  });

  //  Set the timeout to try to turn on if not already
  noReceiveTimeout = setTimeout(function alreadyOn() {
    //  Try to turn on
    self.powerOn(function () {
      //  If it's still not on
      if (DEBUG) {
        console.log('state after power cycle:', self.powerState);
      }
      if (self.powerState === 'off') {
        //  Set the timeout once more
        if (DEBUG) {
          console.log('Trying once more...');
        }
        noReceiveTimeout = setTimeout(function () {
          //  If we still didn't get anything, fail the connect
          noDataRecieved();
        }, 1000);
      }
    });
  }, 1000);
};

GPS.prototype.powerOn = function (callback) {
  /*
  Try to turn the power on. Note that the A2235-H responds to a pulse, not the
  state of the power pin (it toggles).

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  self.power('on', function () {
    setImmediate(function () {
      self.emit('powerOn');
    });
    if (callback) {
      callback();
    }
  });
};

GPS.prototype.powerOff = function (callback) {
  /*
  Try to turn the power off. Note that the A2235-H responds to a pulse, not the
  state of the power pin (it toggles).

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  self.power('off', function () {
    setImmediate(function () {
      self.emit('powerOff');
    });
    if (callback) {
      callback();
    }
  });
};

GPS.prototype.power = function (state, callback) {
  /*
  Toggle the power pin of the A2235-H (attached to hardware.gpio[3]). Assumes
  the module knows what power state it is in.

  Args
    state
      'on' - turn the power on
      'off' - turn the power off
    callback
      Callback function
  */
  //  We need to switch from this state to the given state
  var switchState = (state === 'on' ? 'off' : 'on');
  var self = this;

  //  Pull power high
  if (self.powerState === switchState) {
    if (DEBUG) {
      console.log('high');
    }
    self.onOff.output().high();
    setTimeout(function backLow() {
      if (DEBUG) {
        console.log('low');
      }
      self.onOff.low();
      //  Pull power low
      if (self.powerState === switchState) {
        //  Set a timeout for it to have time to turn on and start sending
        setTimeout(callback, 500);
      }
    }, 250);
  } else if (callback) {
    callback();
  }
};

GPS.prototype.beginDecoding = function (callback) {
  /*
  After making contact with the A2235-H, start decoging its NMEA messages to
  get information from the GPS satellites

  Arg
    callback
      Callback function
  */
  var self = this;
  //  Eventually replace this with stream packetizing... sorry Kolker
  //  Initializer our packetizer
  var packetizer = new Packetizer(this.uart);
  //  Tell it to start packetizing
  packetizer.packetize();
  //  When we get a packet
  packetizer.on('packet', function (packet) {
    if (DEBUG) {
      console.log('  Packet\t', packet);
    }
    //  Make sure this is a valid packet
    if (packet[0] === '$') {
      //  Parse it
      var datum = nmea.parse(packet);

      if (DEBUG) {  //  pretty print
        console.log('    Got Data:');
        Object.keys(datum).forEach(function (key) {
          console.log('     ', key, '\n       ', datum[key]);
          });
        console.log();
      }
      //  If sucessful, emit the parsed NMEA object by its type
      if (datum) {
        setImmediate(function () {
          //  Emit the packet by its type
          self.emit(datum.type, datum);
          //  Emit coordinates if the parsed message contains them
          if (datum.lon && datum.lat) {
            self.emitCoordinates(datum);
          }
          //  Ditto for altitude
          if (datum.alt) {
            self.emitAltitude(datum);
          }
          //  Do whatever else the user maps to specific attributes
          self.executeCallbackss(datum);
        });
      }
    }
  });

  if (callback) {
    callback();
  }
};

GPS.prototype._switchToNMEA9800 = function (callback) {
  /*
  The A2235-H has been configured in hardware to use UART, but we need to send
  it this command so that it gives us NMEA messages as opposed to SiRF binary.

  Arg
    callback
      Callback function
  */
  //  Configure GPS baud rate to 9600, talk in NMEA
  var characters = new Buffer([0xA0, 0xA2, 0x00, 0x18, 0x81, 0x02, 0x01, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x25, 0x80, 0x01, 0x3A, 0xB0, 0xB3]);

  //  Write the message
  this.uart.write(characters);

  //  Reset UART baud rate
  this.uart = this.hardware.UART({baudrate : 9600});

  if (callback) {
    callback();
  }
};

GPS.prototype.setCoordinateFormat = function (format) {
  /*
  Configure how the module reports latitude and longitude

  Arg
    format
      'deg-min-sec' - Degrees + minutes + seconds
      'deg-dec' - Degrees and fractions thereof, as a decimal
      'deg-min-dec' - Degrees + minutes and fractions thereof, as a decimal
      'utm' - Report coordinates in the  Universal Transverse Mercator
        coordinate system. Not currently supported.
  */
  this.format = format;
  if (format === 'utm') {
    //  if at some point we want to go through this pain: http://www.uwgb.edu/dutchs/usefuldata/utmformulas.htm
    console.warn('UTM not currently supported. Voice your outrage to @selkeymoonbeam.');
  } else if (format != 'deg-min-sec' || format != 'deg-dec' ||
    format != 'deg-min-dec') {
    this.format = null;
    console.warn('Invalid format. Must be \'dig-min-sec\', \'deg-dec\', or \'deg-min-dec\'');
  } else {
    this.format = format;
  }
};

GPS.prototype.setCallback = function (attribute, cb, callback) {
  /*
  Set a callback function to be called for NMEA messages containing valid
  forms (!== undefined) of the given attribute.

  Notes
  - There can only be one callback for any given attribute
  - All messages are already emitted by their type (see beginDecoding)
  - Not all message attributes carry the same kind of data in all message types

  Args
    attribute
      The attribute for which the callback will be called
    cb
      Callback function to call with the NMEA message; args: err, parsed (an
        object with the contents of the NMEA message)
    callback
      This function's callback function
  */
  if (this.callbacks[attribute]) {
    console.warn('Overwriting existing directive for', attribute,
      'with', cb);
  }
  this.callbacks[attribute] = callback;
  if (callback) {
    callback();
  }
};

GPS.prototype.removeCallback = function (attribute, callback) {
  /*
  Remove the callback function to be called for NMEA messages containing valid
  forms of the given attribute.
  Note that there can only be one callback for any given attribute.

  Args
    attribute
      The attribute for which the callback will be called. A string.
    callback
      Callback function
  */
  if (this.callbacks[attribute]) {
    delete this.callbacks[attribute];
  } else {
    console.warn('No callback existed for', attribute);
  }
  if (callback) {
    callback();
  }
};

GPS.prototype.executeCallbacks = function (parsed) {
  /*
  Pass the parsed data to the appropriate callback functions, as defined in
  this.callbacks. Called every time we get a NMEA message (see beginDecoding).

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  Object.keys(self.callbacks).forEach(function (key) {
    if (Object.keys(parsed).indexOf(key) !== -1) {  //  Is the key there?
      setImmediate(function (err) {
        self.callbacks[key](err, parsed);
      });
    }
  });
};

GPS.prototype.emitCoordinates = function (parsed) {
  /*
  Format and emit the coordinates in parsed NMEA message

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  if (parsed.lon && parsed.lat) {
    var latPole = parsed.latPole;
    var lonPole = parsed.lonPole;
    var lat = parsed.lat;
    var lon = parsed.lon;
    var dec = lat.indexOf('.');
    var latDeg = parseFloat(lat.slice(0, dec-2));
    var latMin = parseFloat(lat.slice(dec-2, lat.length));
    dec = lon.indexOf('.');
    var lonDeg = parseFloat(lon.slice(0, dec-2));
    var lonMin = parseFloat(lon.slice(dec-2, lon.length));
    var longitude;
    var latitude;
    var latSec;
    var lonSec;

    if (self.format === 'deg-min-sec') {
      latSec = parseFloat(latMin.toString().split('.')[1] * 0.6);
      latMin = parseInt(latMin.toString().split('.')[0]);

      lonSec = parseFloat(lonMin.toString().split('.')[1] * 0.6);
      lonMin = parseInt(lonMin.toString().split('.')[0]);

      latitude = [latDeg, latMin, latSec, latPole];
      longitude = [lonDeg, lonMin, lonSec, lonPole];
    } else if (self.format === 'deg-dec') {
      lat = latDeg + (latMin / 60);
      lon = lonDeg + (lonMin / 60);

      latitude = [lat, latPole];
      longitude = [lon, lonPole];
    } else {
      latitude = [latDeg, latMin, latPole];
      longitude = [lonDeg, lonMin, lonPole];
    }
    var coordinates = {lat: latitude, lon: longitude,
      timestamp: parseFloat(parsed.timestamp)};

    setImmediate(function () {
      self.emit('coordinates', coordinates);
    });
  }
};

GPS.prototype.emitAltitude = function (parsed) {
  /*
  Emit the altitude in the given parsed NMEA message

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  if (parsed.alt) {

    parsed.alt = parseInt(parsed.alt);

    setImmediate(function () {
      self.emit('altitude', {alt: parsed.alt,
        timestamp: parseFloat(parsed.timestamp)});
    });
  }
};

// //  GPS.prototype.geofence = function (minCoordinates, maxCoordinates) {
// // 	//  takes in coordinates, draws a rectangle from minCoordinates to maxCoordinates
// // 	//  returns boolean 'inRange' which is true when coordinates are in the rectangle
// // 	var buffer = this.cached;
// // 	var inRange = false;
// // 	if ((minCoordinates.lat.length === 2) && (maxCoordinates.lat.length === 2)) {
// // 		if (minCoordinates.lat[1] === 'S') {
// // 			minLat = -minCoordinates.lat[0];
// // 		} else {minLat = minCoordinates.lat[0]}
// // 		if (minCoordinates.lon[1] === 'W') {
// // 			minLon = -minCoordinates.lon[0];
// // 		} else {minLon = minCoordinates.lon[0]}
// // 		if (maxCoordinates.lat[1] === 'S') {
// // 			maxLat = -maxCoordinates.lat[0];
// // 		} else {maxLat = maxCoordinates.lat[0]}
// // 		if (maxCoordinates.lon[1] === 'W') {
// // 			maxLon = -maxCoordinates.lon[0];
// // 		} else {maxLon = maxCoordinates.lon[0]}

// // 		//get current coordinates
// // 		currentCoords = this.getCoordinates(this.cached);
// // 		if (currentCoords != 'no navigation data in buffer') {
// // 			if (currentCoords.lat[1] === 'S') {
// // 				currentLat = -currentCoords.lat[0];
// // 			} else {currentLat = currentCoords.lat[0]}
// // 			if (currentCoords.lon[1] === 'W') {
// // 				currentLon = -currentCoords.lon[0];
// // 			} else {currentLon = currentCoords.lon[0]}

// // 			//compare current coordinates with geofence
// // 			if ((currentLat > minLat) && (currentLat < maxLat) && (currentLon > minLon) && (currentLon < maxLon)) {
// // 				inRange = true;
// // 			} else {inRange = false}
// // 			var timestamp = currentCoords.timestamp;
// // 			return {inRange: inRange, timestamp: timestamp}
// // 		} else {return 'no position data'}
// // 	} else {return 'please use deg-dec coordinates'}
// // }

var connect = function (hardware) {
	return new GPS(hardware);
};

module.exports.connect = connect;
module.exports.GPS = GPS;
<commit_msg>callback was in the wrong place<commit_after>var util = require('util');
var EventEmitter = require('events').EventEmitter;
var nmea = require('nmea');
var Packetizer = require('./lib/packetizer');

var DEBUG = true;  //  Set to true for debug console logs

var GPS = function (hardware, callback) {
  /*
  Constructor

  Args
    hardware
      The Tessel port to use
    callback
      Callback function
  */
  var self = this;
  //set this.types for each type
  //type: fix, nav-info, 2waypoint, autopilot-b
  this.hardware = hardware;
  this.onOff = this.hardware.gpio(3);
  this.powerState = 'off';
  this.timeoutDuration = 10*1000;
  this.format = 'deg-min-dec';
  //  A collection of attributes and callback functions. See set/removeCallbacks.
  this.callbacks = {};

  //  Turn the module on
  self.initialPowerSequence(function (err) {
    if (!err) {
      //  Once we are on, emit the connected event
      self.beginDecoding(function () {

        setImmediate(function () {
          self.emit('ready');
        });
      });
    } else {
      setImmediate(function () {
        self.emit('error', err);
      });
    }
    if (callback) {
      callback();
    }
  });
};

util.inherits(GPS, EventEmitter);

GPS.prototype.initialPowerSequence = function (callback) {
  /*
  Turn on and establish contact with the A2235-H GPS module

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  //  Tell Tessel to start UART at GPS baud rate
  this.uart = this.hardware.UART({baudrate : 115200});

  var noReceiveTimeout;

  function waitForData () {
    //  Remove this listener when we hear something (anything) from the GPS
    self.uart.removeListener('data', waitForData);

    clearTimeout(noReceiveTimeout);

    //  And note that we are on
    self.powerState = 'on';

    //  Tell the A2235-H that we want it to give us NMEA strings over UART
    self._switchToNMEA9800(callback);
  }

  function noDataRecieved () {
    //  Remove the listener for any data
    self.uart.removeListener('data', waitForData);
    //  Clear the timeout
    clearTimeout(noReceiveTimeout);
    //  Call the callback
    if (callback) {
      callback(new Error('Unable to connect to module...'));
    }
  }

  /*
  Wait for a second to see if we get data. If we do, call callback;
  If we don't, toggle power and set timeout again
  If we still don't get it, something bigger is wrong
  */

  //  This event listener will wait for valid data to note that we are on
  self.uart.once('data', function (data) {
    waitForData(data);
  });

  //  Set the timeout to try to turn on if not already
  noReceiveTimeout = setTimeout(function alreadyOn() {
    //  Try to turn on
    self.powerOn(function () {
      //  If it's still not on
      if (DEBUG) {
        console.log('state after power cycle:', self.powerState);
      }
      if (self.powerState === 'off') {
        //  Set the timeout once more
        if (DEBUG) {
          console.log('Trying once more...');
        }
        noReceiveTimeout = setTimeout(function () {
          //  If we still didn't get anything, fail the connect
          noDataRecieved();
        }, 1000);
      }
    });
  }, 1000);
};

GPS.prototype.powerOn = function (callback) {
  /*
  Try to turn the power on. Note that the A2235-H responds to a pulse, not the
  state of the power pin (it toggles).

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  self.power('on', function () {
    setImmediate(function () {
      self.emit('powerOn');
    });
    if (callback) {
      callback();
    }
  });
};

GPS.prototype.powerOff = function (callback) {
  /*
  Try to turn the power off. Note that the A2235-H responds to a pulse, not the
  state of the power pin (it toggles).

  Arg
    callback
      Callback function; arg: err
  */
  var self = this;
  self.power('off', function () {
    setImmediate(function () {
      self.emit('powerOff');
    });
    if (callback) {
      callback();
    }
  });
};

GPS.prototype.power = function (state, callback) {
  /*
  Toggle the power pin of the A2235-H (attached to hardware.gpio[3]). Assumes
  the module knows what power state it is in.

  Args
    state
      'on' - turn the power on
      'off' - turn the power off
    callback
      Callback function
  */
  //  We need to switch from this state to the given state
  var switchState = (state === 'on' ? 'off' : 'on');
  var self = this;

  //  Pull power high
  if (self.powerState === switchState) {
    if (DEBUG) {
      console.log('high');
    }
    self.onOff.output().high();
    setTimeout(function backLow() {
      if (DEBUG) {
        console.log('low');
      }
      self.onOff.low();
      //  Pull power low
      if (self.powerState === switchState) {
        //  Set a timeout for it to have time to turn on and start sending
        setTimeout(callback, 500);
      }
    }, 250);
  } else if (callback) {
    callback();
  }
};

GPS.prototype.beginDecoding = function (callback) {
  /*
  After making contact with the A2235-H, start decoging its NMEA messages to
  get information from the GPS satellites

  Arg
    callback
      Callback function
  */
  var self = this;
  //  Eventually replace this with stream packetizing... sorry Kolker
  //  Initializer our packetizer
  var packetizer = new Packetizer(this.uart);
  //  Tell it to start packetizing
  packetizer.packetize();
  //  When we get a packet
  packetizer.on('packet', function (packet) {
    if (DEBUG) {
      console.log('  Packet\t', packet);
    }
    //  Make sure this is a valid packet
    if (packet[0] === '$') {
      //  Parse it
      var datum = nmea.parse(packet);

      if (DEBUG) {  //  pretty print
        console.log('    Got Data:');
        Object.keys(datum).forEach(function (key) {
          console.log('     ', key, '\n       ', datum[key]);
          });
        console.log();
      }
      //  If sucessful, emit the parsed NMEA object by its type
      if (datum) {
        setImmediate(function () {
          //  Emit the packet by its type
          self.emit(datum.type, datum);
          //  Emit coordinates if the parsed message contains them
          if (datum.lon && datum.lat) {
            self.emitCoordinates(datum);
          }
          //  Ditto for altitude
          if (datum.alt) {
            self.emitAltitude(datum);
          }
          //  Do whatever else the user maps to specific attributes
          self.executeCallbackss(datum);
        });
      }
    }
  });

  if (callback) {
    callback();
  }
};

GPS.prototype._switchToNMEA9800 = function (callback) {
  /*
  The A2235-H has been configured in hardware to use UART, but we need to send
  it this command so that it gives us NMEA messages as opposed to SiRF binary.

  Arg
    callback
      Callback function
  */
  //  Configure GPS baud rate to 9600, talk in NMEA
  var characters = new Buffer([0xA0, 0xA2, 0x00, 0x18, 0x81, 0x02, 0x01, 0x01,
    0x00, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x25, 0x80, 0x01, 0x3A, 0xB0, 0xB3]);

  //  Write the message
  this.uart.write(characters);

  //  Reset UART baud rate
  this.uart = this.hardware.UART({baudrate : 9600});

  if (callback) {
    callback();
  }
};

GPS.prototype.setCoordinateFormat = function (format) {
  /*
  Configure how the module reports latitude and longitude

  Arg
    format
      'deg-min-sec' - Degrees + minutes + seconds
      'deg-dec' - Degrees and fractions thereof, as a decimal
      'deg-min-dec' - Degrees + minutes and fractions thereof, as a decimal
      'utm' - Report coordinates in the  Universal Transverse Mercator
        coordinate system. Not currently supported.
  */
  this.format = format;
  if (format === 'utm') {
    //  if at some point we want to go through this pain: http://www.uwgb.edu/dutchs/usefuldata/utmformulas.htm
    console.warn('UTM not currently supported. Voice your outrage to @selkeymoonbeam.');
  } else if (format != 'deg-min-sec' || format != 'deg-dec' ||
    format != 'deg-min-dec') {
    this.format = null;
    console.warn('Invalid format. Must be \'dig-min-sec\', \'deg-dec\', or \'deg-min-dec\'');
  } else {
    this.format = format;
  }
};

GPS.prototype.setCallback = function (attribute, cb, callback) {
  /*
  Set a callback function to be called for NMEA messages containing valid
  forms (!== undefined) of the given attribute.

  Notes
  - There can only be one callback for any given attribute
  - All messages are already emitted by their type (see beginDecoding)
  - Not all message attributes carry the same kind of data in all message types

  Args
    attribute
      The attribute for which the callback will be called
    cb
      Callback function to call with the NMEA message; args: err, parsed (an
        object with the contents of the NMEA message)
    callback
      This function's callback function
  */
  if (this.callbacks[attribute]) {
    console.warn('Overwriting existing directive for', attribute,
      'with', cb);
  }
  this.callbacks[attribute] = callback;
  if (callback) {
    callback();
  }
};

GPS.prototype.removeCallback = function (attribute, callback) {
  /*
  Remove the callback function to be called for NMEA messages containing valid
  forms of the given attribute.
  Note that there can only be one callback for any given attribute.

  Args
    attribute
      The attribute for which the callback will be called. A string.
    callback
      Callback function
  */
  if (this.callbacks[attribute]) {
    delete this.callbacks[attribute];
  } else {
    console.warn('No callback existed for', attribute);
  }
  if (callback) {
    callback();
  }
};

GPS.prototype.executeCallbacks = function (parsed) {
  /*
  Pass the parsed data to the appropriate callback functions, as defined in
  this.callbacks. Called every time we get a NMEA message (see beginDecoding).

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  Object.keys(self.callbacks).forEach(function (key) {
    if (Object.keys(parsed).indexOf(key) !== -1) {  //  Is the key there?
      setImmediate(function (err) {
        self.callbacks[key](err, parsed);
      });
    }
  });
};

GPS.prototype.emitCoordinates = function (parsed) {
  /*
  Format and emit the coordinates in parsed NMEA message

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  if (parsed.lon && parsed.lat) {
    var latPole = parsed.latPole;
    var lonPole = parsed.lonPole;
    var lat = parsed.lat;
    var lon = parsed.lon;
    var dec = lat.indexOf('.');
    var latDeg = parseFloat(lat.slice(0, dec-2));
    var latMin = parseFloat(lat.slice(dec-2, lat.length));
    dec = lon.indexOf('.');
    var lonDeg = parseFloat(lon.slice(0, dec-2));
    var lonMin = parseFloat(lon.slice(dec-2, lon.length));
    var longitude;
    var latitude;
    var latSec;
    var lonSec;

    if (self.format === 'deg-min-sec') {
      latSec = parseFloat(latMin.toString().split('.')[1] * 0.6);
      latMin = parseInt(latMin.toString().split('.')[0]);

      lonSec = parseFloat(lonMin.toString().split('.')[1] * 0.6);
      lonMin = parseInt(lonMin.toString().split('.')[0]);

      latitude = [latDeg, latMin, latSec, latPole];
      longitude = [lonDeg, lonMin, lonSec, lonPole];
    } else if (self.format === 'deg-dec') {
      lat = latDeg + (latMin / 60);
      lon = lonDeg + (lonMin / 60);

      latitude = [lat, latPole];
      longitude = [lon, lonPole];
    } else {
      latitude = [latDeg, latMin, latPole];
      longitude = [lonDeg, lonMin, lonPole];
    }
    var coordinates = {lat: latitude, lon: longitude,
      timestamp: parseFloat(parsed.timestamp)};

    setImmediate(function () {
      self.emit('coordinates', coordinates);
    });
  }
};

GPS.prototype.emitAltitude = function (parsed) {
  /*
  Emit the altitude in the given parsed NMEA message

  Arg
    parsed
      The output of nmea.parse(): an object containing the parsed NEMA message
  */
  var self = this;
  if (parsed.alt) {

    parsed.alt = parseInt(parsed.alt);

    setImmediate(function () {
      self.emit('altitude', {alt: parsed.alt,
        timestamp: parseFloat(parsed.timestamp)});
    });
  }
};

// //  GPS.prototype.geofence = function (minCoordinates, maxCoordinates) {
// // 	//  takes in coordinates, draws a rectangle from minCoordinates to maxCoordinates
// // 	//  returns boolean 'inRange' which is true when coordinates are in the rectangle
// // 	var buffer = this.cached;
// // 	var inRange = false;
// // 	if ((minCoordinates.lat.length === 2) && (maxCoordinates.lat.length === 2)) {
// // 		if (minCoordinates.lat[1] === 'S') {
// // 			minLat = -minCoordinates.lat[0];
// // 		} else {minLat = minCoordinates.lat[0]}
// // 		if (minCoordinates.lon[1] === 'W') {
// // 			minLon = -minCoordinates.lon[0];
// // 		} else {minLon = minCoordinates.lon[0]}
// // 		if (maxCoordinates.lat[1] === 'S') {
// // 			maxLat = -maxCoordinates.lat[0];
// // 		} else {maxLat = maxCoordinates.lat[0]}
// // 		if (maxCoordinates.lon[1] === 'W') {
// // 			maxLon = -maxCoordinates.lon[0];
// // 		} else {maxLon = maxCoordinates.lon[0]}

// // 		//get current coordinates
// // 		currentCoords = this.getCoordinates(this.cached);
// // 		if (currentCoords != 'no navigation data in buffer') {
// // 			if (currentCoords.lat[1] === 'S') {
// // 				currentLat = -currentCoords.lat[0];
// // 			} else {currentLat = currentCoords.lat[0]}
// // 			if (currentCoords.lon[1] === 'W') {
// // 				currentLon = -currentCoords.lon[0];
// // 			} else {currentLon = currentCoords.lon[0]}

// // 			//compare current coordinates with geofence
// // 			if ((currentLat > minLat) && (currentLat < maxLat) && (currentLon > minLon) && (currentLon < maxLon)) {
// // 				inRange = true;
// // 			} else {inRange = false}
// // 			var timestamp = currentCoords.timestamp;
// // 			return {inRange: inRange, timestamp: timestamp}
// // 		} else {return 'no position data'}
// // 	} else {return 'please use deg-dec coordinates'}
// // }

var connect = function (hardware) {
	return new GPS(hardware);
};

module.exports.connect = connect;
module.exports.GPS = GPS;
<|endoftext|>


<commit_before>//config
var port = 8000;
var logLevel = 'debug';

//api calls
//62.101.1.162 is efa.mobilitaetsagentur.bz.it
var BUSSTOP_QUERY = 'http://62.101.1.162/apb/XSLT_STOPFINDER_REQUEST?language=de&outputFormat=JSON&itdLPxx_usage=origin&useLocalityMainStop=true&doNotSearchForStops_sf=1&SpEncId=1&odvSugMacro=true&name_sf=';
var STATIONBOARD_QUERY = 'http://62.101.1.162/apb/XSLT_DM_REQUEST?language=de&deleteAssignedStops_dm=1&trITMOTvalue100=7&useProxFootSearch=0&itdLPxx_today=10&mode=direct&lsShowTrainsExplicit=0&type_dm=any&includedMeans=checkbox&inclMOT_ZUG=1&inclMOT_BUS=1&inclMOT_8=1&inclMOT_9=1&locationServerActive=1&convertStopsPTKernel2LocationServer=1&convertAddressesITKernel2LocationServer=1&convertCoord2LocationServer=1&convertCrossingsITKernel2LocationServer=1&convertPOIsITKernel2LocationServer=1&stateless=1&itOptionsActive=1&ptOptionsActive=1&itdLPxx_depOnly=1&maxAssignedStops=1&hideBannerInfo=1&execInst=normal&limit=15&useAllStops=1&outputFormat=JSON&name_dm=';

/*
 * Log level:
 *
 * 0 EMERGENCY system is unusable
 * 1 ALERT action must be taken immediately
 * 2 CRITICAL the system is in critical condition
 * 3 ERROR error condition
 * 4 WARNING warning condition
 * 5 NOTICE a normal but significant condition
 * 6 INFO a purely informational message
 * 7 DEBUG messages to debug an application
 */

var Log = require('log');
var request = require('request');
var moment = require('moment');
var sortBy = require("sort-array");
var WebSocketServer = require('ws').Server;

var log = new Log(logLevel);
var wss = new WebSocketServer({ port: port });

log.info("WebSocket listening on " + port);

wss.on('connection', function connection(ws) {
	log.info("New client connected");
	ws.on('message', function incoming(message) {
		log.info('received: %s', message);
		try {
			message = JSON.parse(message);
			if (message.call !== undefined && message.query !==undefined) {
				if (message.call == "busstopRequest")
					busstopRequest(message.query, ws);
				else if (message.call == "stationboardRequest")
					stationboardRequest(message.query, ws);
				else
					log.info("Unknown call");
			}
			else
				log.info("Missing argument");
		} catch (exc) {
			log.error("JSON parse error:", exc);
		}
	});
});

function busstopRequest(query, ws) {
	var list = [];
	console.time("Request Time");
	request(BUSSTOP_QUERY + query, function(err, res, body) {
		console.timeEnd("Request Time");
		if(!err) {
			try {
				var busstopList = JSON.parse(body).stopFinder.points;
				if (busstopList !== null) {
					if (busstopList.point !== undefined) {
						list.push(parseBusstop(busstopList.point));
					}
					else {
						sortBy(busstopList, "quality");
						for (var i = 0; i < busstopList.length; i++) {
							if (busstopList[i].anyType == "stop") {
								list.push(parseBusstop(busstopList[i]));
							}
						}
					}
				}
				log.debug("Busstop List:", JSON.stringify(list));
				if (ws)
					ws.send(JSON.stringify({res: list, cb: "busstopResponse"}));
			} catch (exc) {
				log.error("JSON parse error:", exc);
			}
		}
		else
			log.error("HTTP error:", err);
	});
}

function parseBusstop(el) {
	var res = {};
	res.name = el.object;
	res.city = el.posttown;
	res.id = el.stateless;
	return res;
}

function stationboardRequest(query, ws) {
	var list = [];
	request(STATIONBOARD_QUERY + query, function(err, res, body) {
		if(!err) {
			try {
				var departureList = JSON.parse(body).departureList;
				for (var i = 0; i < departureList.length; i++) {
					list.push(parseStationboard(departureList[i]));
				}
				log.debug("Stationboard List:", JSON.stringify(list));
				if (ws)
					ws.send(JSON.stringify({res: list, cb: "stationboardResponse"}));
			} catch (exc) {
				log.error("JSON parse error:", exc);
			}
		}
		else
			log.error("HTTP error:", err);
	});
}

function parseStationboard(el) {
	var res = {};
	/*year, month, day, hour,	minute*/
	var d = el.dateTime;
	/*2013-10-21T13:28:06.419Z*/
	res.dateTime = moment(d.year + "-" + d.month + "-" + d.day + "," + d.hour + ":" + d.minute, "YYYY-MM-DD,HH:mm").format();
	res.countdown = el.countdown;
	res.direction = el.servingLine.direction;
	res.number = el.servingLine.number;
	res.symbol = el.servingLine.symbol;
	return res;
}
<commit_msg>[feat] add gzip support for api calls --> increased api speed<commit_after>//config
var port = 8000;
var logLevel = 'info';

//api calls
//62.101.1.162 is efa.mobilitaetsagentur.bz.it
var BUSSTOP_QUERY = 'http://62.101.1.162/apb/XSLT_STOPFINDER_REQUEST?language=de&outputFormat=JSON&itdLPxx_usage=origin&useLocalityMainStop=true&doNotSearchForStops_sf=1&SpEncId=1&odvSugMacro=true&name_sf=';
var STATIONBOARD_QUERY = 'http://62.101.1.162/apb/XSLT_DM_REQUEST?language=de&deleteAssignedStops_dm=1&trITMOTvalue100=7&useProxFootSearch=0&itdLPxx_today=10&mode=direct&lsShowTrainsExplicit=0&type_dm=any&includedMeans=checkbox&inclMOT_ZUG=1&inclMOT_BUS=1&inclMOT_8=1&inclMOT_9=1&locationServerActive=1&convertStopsPTKernel2LocationServer=1&convertAddressesITKernel2LocationServer=1&convertCoord2LocationServer=1&convertCrossingsITKernel2LocationServer=1&convertPOIsITKernel2LocationServer=1&stateless=1&itOptionsActive=1&ptOptionsActive=1&itdLPxx_depOnly=1&maxAssignedStops=1&hideBannerInfo=1&execInst=normal&limit=15&useAllStops=1&outputFormat=JSON&name_dm=';

/*
 * Log level:
 *
 * 0 EMERGENCY system is unusable
 * 1 ALERT action must be taken immediately
 * 2 CRITICAL the system is in critical condition
 * 3 ERROR error condition
 * 4 WARNING warning condition
 * 5 NOTICE a normal but significant condition
 * 6 INFO a purely informational message
 * 7 DEBUG messages to debug an application
 */

var Log = require('log');
var request = require('request');
var moment = require('moment');
var sortBy = require("sort-array");
var WebSocketServer = require('ws').Server;

var log = new Log(logLevel);
var wss = new WebSocketServer({ port: port });

log.info("WebSocket listening on " + port);

wss.on('connection', function connection(ws) {
	log.info("New client connected");
	ws.on('message', function incoming(message) {
		log.info('received: %s', message);
		try {
			message = JSON.parse(message);
			if (message.call !== undefined && message.query !==undefined) {
				if (message.call == "busstopRequest")
					busstopRequest(message.query, ws);
				else if (message.call == "stationboardRequest")
					stationboardRequest(message.query, ws);
				else
					log.info("Unknown call");
			}
			else
				log.info("Missing argument");
		} catch (exc) {
			log.error("JSON parse error:", exc);
		}
	});
});

function busstopRequest(query, ws) {
	var list = [];
	console.time("Request Time");
	request({url: BUSSTOP_QUERY + query,
		json: true,
		gzip: true,
		headers: {
			'Connection': 'keep-alive',
			'Accept-Encoding': 'gzip, deflate'
		}
	},
	function(err, res, body) {
		console.timeEnd("Request Time");
		if(!err) {
			try {
				//var busstopList = JSON.parse(body).stopFinder.points;
				log.debug(body);
				var busstopList = body.stopFinder.points;
				if (busstopList !== null) {
					if (busstopList.point !== undefined) {
						list.push(parseBusstop(busstopList.point));
					}
					else {
						sortBy(busstopList, "quality");
						for (var i = 0; i < busstopList.length; i++) {
							if (busstopList[i].anyType == "stop") {
								list.push(parseBusstop(busstopList[i]));
							}
						}
					}
				}
				log.debug("Busstop List:", JSON.stringify(list));
				if (ws)
					ws.send(JSON.stringify({res: list, cb: "busstopResponse"}));
			} catch (exc) {
				log.error("JSON parse error:", exc);
			}
		}
		else
			log.error("HTTP error:", err);
	});
}

function parseBusstop(el) {
	var res = {};
	res.name = el.object;
	res.city = el.posttown;
	res.id = el.stateless;
	return res;
}

function stationboardRequest(query, ws) {
	var list = [];
	request({url: STATIONBOARD_QUERY + query,
		json: true,
		gzip: true,
		headers: {
			'Connection': 'keep-alive',
			'Accept-Encoding': 'gzip, deflate'
		}
	},
	function(err, res, body) {
		if(!err) {
			try {
				//var departureList = JSON.parse(body).departureList;
				var departureList = body.departureList;
				for (var i = 0; i < departureList.length; i++) {
					list.push(parseStationboard(departureList[i]));
				}
				log.debug("Stationboard List:", JSON.stringify(list));
				if (ws)
					ws.send(JSON.stringify({res: list, cb: "stationboardResponse"}));
			} catch (exc) {
				log.error("JSON parse error:", exc);
			}
		}
		else
			log.error("HTTP error:", err);
	});
}

function parseStationboard(el) {
	var res = {};
	/*year, month, day, hour,	minute*/
	var d = el.dateTime;
	/*2013-10-21T13:28:06.419Z*/
	res.dateTime = moment(d.year + "-" + d.month + "-" + d.day + "," + d.hour + ":" + d.minute, "YYYY-MM-DD,HH:mm").format();
	res.countdown = el.countdown;
	res.direction = el.servingLine.direction;
	res.number = el.servingLine.number;
	res.symbol = el.servingLine.symbol;
	return res;
}
<|endoftext|>


<commit_before>/*!
 * error-base <https://github.com/doowb/error-base>
 *
 * Copyright (c) 2015, Brian Woodward.
 * Licensed under the MIT License.
 */

'use strict';

/**
 * Code modified from http://stackoverflow.com/a/27925672/914583
 *
 * ```js
 * var CustomError = errorBase('CustomError', function (msg) {
 *   this.msg = msg;
 * });
 * ```
 *
 * @param  {String} `name` Name of new Error Class
 * @param  {Function} `init` Function to call when creating new Error
 * @return {Function} new Error Class
 * @api public
 * @name  errorBase
 */

module.exports = function errorBase (name, init) {
  if (typeof name !== 'string') {
    throw new TypeError('expected `name` to be a string.');
  }

  if (typeof init !== 'function') {
    init = identity;
  }

  function Type () {
    if (!Error.captureStackTrace) {
      this.stack = (new Error()).stack;
    }
    else {
      Error.captureStackTrace(this, this.constructor);
    }

    init.apply(this, arguments);
  }

  Type.prototype = new Error();
  Type.prototype.name = name;
  Type.prototype.constructor = Type;

  return Type;
};

function identity (message) {
  this.message = message;
}
<commit_msg>add option to not capture stacktraces<commit_after>/*!
 * error-base <https://github.com/doowb/error-base>
 *
 * Copyright (c) 2015, Brian Woodward.
 * Licensed under the MIT License.
 */

'use strict';

/**
 * Code modified from http://stackoverflow.com/a/27925672/914583
 *
 * ```js
 * var CustomError = errorBase('CustomError', function (msg) {
 *   this.msg = msg;
 * });
 * ```
 *
 * @param  {String} `name` Name of new Error Class
 * @param  {Function} `init` Function to call when creating new Error
 * @return {Function} new Error Class
 * @api public
 * @name  errorBase
 */

module.exports = function errorBase (name, init, capture) {
  if (typeof name !== 'string') {
    throw new TypeError('expected `name` to be a string.');
  }

  if (typeof init !== 'function') {
    init = identity;
  }
  capture = typeof capture === 'boolean' ? capture : true;

  function Type () {
    if (!Error.captureStackTrace) {
      if (capture) this.stack = (new Error()).stack;
    } else {
      if (capture) Error.captureStackTrace(this, this.constructor);
    }

    init.apply(this, arguments);
  }

  Type.prototype = Object.create(Error.prototype);
  Type.prototype.name = name;
  Type.prototype.constructor = Type;

  return Type;
};

function identity (message) {
  this.message = message;
}
<|endoftext|>


<commit_before>var child = require('child_process');
var chokidar = require('chokidar');
var fs = require('fs');
var http = require('http');
var mime = require('mime');
var path = require('path');
var rdbg = require('rdbg');
var util = require('util');
var temp = require('temp');
var which = require('which');
var url = require('url');

function serve(options, callback) {
  var server = http.createServer();

  var scripts = options.scripts || {};
  var cwd = options.cwd | process.cwd()

  server.on('request', function(request, response) {
    if (request.url === '/') {
      request.url = '/index.html';
    }

    var location = url.parse(request.url);
    var filename = path.join(options.cwd, location.pathname);

    for (var name in options.scripts) {
      if (options.scripts.hasOwnProperty(name)) {
        if (options.scripts[name] === location.pathname) {
          filename = name;
          break;
        }
      }
    }

    fs.exists(filename, function(exists) {
      if (exists) {
        response.setHeader('content-type', mime.lookup(filename));
        response.writeHead(200);

        var file = fs.createReadStream(filename);
        file.pipe(response);
      } else if (filename === '/index.html') {
        response.setHeader('content-type', 'text/html');
        response.write('<!doctype html><meta charset="utf-8">');

        for (var name in options.scripts) {
          if (options.scripts.hasOwnProperty(name)) {
            response.write('');
          }
        }

        response.end('');
      } else {
        response.writeHead(404);
        response.end('404');
      }
    });
  });

  server.listen(options.port, options.host, callback);
  return server;
}

function compile(options, callback) {
  var dirpath = temp.mkdirSync('amok-output');
  options.output = path.join(dirpath, path.basename(options.args[0].replace(/\.[^\.]+$/, '.js')));

  var args = options.compiler.match(/'[^"]*'|"[^"]*"|\S+/g);
  var command = args.shift();

  switch (options.compiler) {
    case 'browserify':
      command = which.sync('watchify');
      args = [
        '-o',
        options.output,
      ];
      break;

    case 'webpack':
      command = which.sync('webpack');
      args = [
        '--watch',
        '--output-file',
        options.output,
      ];
      break;

    case 'typescript':
      command = which.sync('tsc');
      args = [
        '--watch',
        '--out',
        options.output,
      ];
      break;

    case 'coffeescript':
      command = which.sync('coffee');
      args = [
        '--watch',
        '--compile',
        '--output',
        dirpath,
      ];
      break;

    case 'babel':
      command = which.sync('babel');
      args = [
        '--watch',
        '--out-file',
        options.output,
      ];
      break;
  }

  args = args.concat(options.args);

  var compiler = child.spawn(command, args);
  compiler.output = options.output;

  process.nextTick(function tick() {
    fs.exists(compiler.output, function(exists) {
      if (exists) {
        callback(null, compiler.stdout, compiler.stderr);
      } else {
        setTimeout(tick, 100);
      }
    });
  });

  return compiler;
}

function watch(options, callback) {
  var scripts = options.scripts || {};
  var cwd = options.cwd || process.cwd();

  var watcher = chokidar.watch(options.watch, {
    persistent: true
  });

  for (var name in scripts) {
    if (scripts.hasOwnProperty(name)) {
      var basename = path.basename(name);
      watcher.add(basename);
    }
  }

  var bugger = options.bugger;
  if (bugger) {
    var resolve = function(filename) {
      console.log(filename);
      console.log(scripts);

      if (scripts[filename]) {
        return scripts[filename];
      }

    };

    var emit = function(event, filename) {
      var source = 'if (typeof(window) !== \'undefined\') {'
                 + '  var e = new CustomEvent(\''+ event + '\','
                 + '    { detail: \'' + filename +'\' });'
                 + ''
                 + '  window.dispatchEvent(e);'
                 + '}';
                 + ''
                 + 'if (typeof(process) !== \'undefined\') {'
                 + '  process.emit(\'' + event + '\', \'' + filename + '\');'
                 + '}';

      bugger.evaluate(source, function(error, result) {
        if (error) {
          bugger.emit('error', error);
        }
      });
    };

    watcher.on('add', function(filename) {
      var pathname = resolve(filename);
      emit('add', pathname);
    });

    watcher.on('remove', function(filename) {
      var pathname = resolve(filename);
      emit('remove', pathname);
    });

    watcher.on('change', function(filename) {
      var pathname = resolve(filename);
      emit('change', filename);

      bugger.scripts(function(scripts) {
        var script = scripts.filter(function(script) {
          var location = url.parse(script.url);
          return path.relative('/', location.path || '') === pathname;
        })[0];

        if (script === undefined) {
          return;
        }

        fs.readFile(filename, 'utf-8', function(error, contents) {
          if (error) {
            return bugger.emit('error', error);
          }

          bugger.source(script, contents);
        });
      });
    });

    bugger.on('source', function(script) {
      var location = url.parse(script.url);
      var pathname = path.relative('/', location.pathname || '');
      emit('source', pathname);
    });
  }

  if (callback) {
    watcher.once('ready', callback);
  }

  return watcher;
}

function debug(options, callback) {
  var bugger = rdbg.connect(options.debuggerPort, options.debuggerHost, function(target) {
    callback(null, target);
  });

  bugger.on('detatch', function() {
    var interval = setInterval(function() {
      bugger.targets(function(targets) {
        var target = targets.filter(function(target) {
          return target.url.search(options.url) > -1 && target.webSocketDebuggerUrl;
        })[0];

        if (target) {
          bugger.attach(target);
          clearInterval(interval);
        }
      });
    }, 250);
  });

  bugger.targets(function(targets) {
    var target = targets.filter(function(target) {
      return target.url.search(options.url) > -1 && target.webSocketDebuggerUrl;
    })[0];

    bugger.attach(target);
  });

  return bugger;
}

function open(options, callback) {
  var args = options.client.match(/'[^"]*'|"[^"]*"|\S+/g);
  var command = args.shift();

  switch (options.client) {
    case 'chrome':
      command = (function() {
        if (process.platform === 'win32') {
          var suffix = '\\Google\\Chrome\\Application\\chrome.exe';
          var prefixes = [
            process.env['LOCALAPPDATA'],
            process.env['PROGRAMFILES'],
            process.env['PROGRAMFILES(X86)'],
          ];

          var executables = prefixes.map(function(prefix) {
            return prefix + suffix;
          }).filter(function(path) {
            return fs.existsSync(path);
          });
          return executables[0];
        } else if (process.platform === 'darwin') {
          return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
        } else {
          return which.sync('google-chrome');
        }
      }());

      args = [
        '--remote-debugging-port=' + options.debuggerPort,
        '--no-first-run',
        '--no-default-browser-check',
        '--disable-translate',
        '--disable-default-apps',
        '--disable-popup-blocking',
        '--disable-zero-browsers-open-for-tests',
        '--user-data-dir=' + temp.mkdirSync('amok-chrome'),
      ];
      break;
  }

  args.push(options.url);

  var client = child.spawn(command, args);
  setTimeout(function() {
    callback(null, client.stdout, client.stderr);
  }, 1000);

  return client;
}

module.exports.serve = serve;
module.exports.watch = watch;
module.exports.compile = compile;
module.exports.debug = debug;
module.exports.open = open;
<commit_msg>Remove stray console logs<commit_after>var child = require('child_process');
var chokidar = require('chokidar');
var fs = require('fs');
var http = require('http');
var mime = require('mime');
var path = require('path');
var rdbg = require('rdbg');
var util = require('util');
var temp = require('temp');
var which = require('which');
var url = require('url');

function serve(options, callback) {
  var server = http.createServer();

  var scripts = options.scripts || {};
  var cwd = options.cwd | process.cwd()

  server.on('request', function(request, response) {
    if (request.url === '/') {
      request.url = '/index.html';
    }

    var location = url.parse(request.url);
    var filename = path.join(options.cwd, location.pathname);

    for (var name in options.scripts) {
      if (options.scripts.hasOwnProperty(name)) {
        if (options.scripts[name] === location.pathname) {
          filename = name;
          break;
        }
      }
    }

    fs.exists(filename, function(exists) {
      if (exists) {
        response.setHeader('content-type', mime.lookup(filename));
        response.writeHead(200);

        var file = fs.createReadStream(filename);
        file.pipe(response);
      } else if (filename === '/index.html') {
        response.setHeader('content-type', 'text/html');
        response.write('<!doctype html><meta charset="utf-8">');

        for (var name in options.scripts) {
          if (options.scripts.hasOwnProperty(name)) {
            response.write('');
          }
        }

        response.end('');
      } else {
        response.writeHead(404);
        response.end('404');
      }
    });
  });

  server.listen(options.port, options.host, callback);
  return server;
}

function compile(options, callback) {
  var dirpath = temp.mkdirSync('amok-output');
  options.output = path.join(dirpath, path.basename(options.args[0].replace(/\.[^\.]+$/, '.js')));

  var args = options.compiler.match(/'[^"]*'|"[^"]*"|\S+/g);
  var command = args.shift();

  switch (options.compiler) {
    case 'browserify':
      command = which.sync('watchify');
      args = [
        '-o',
        options.output,
      ];
      break;

    case 'webpack':
      command = which.sync('webpack');
      args = [
        '--watch',
        '--output-file',
        options.output,
      ];
      break;

    case 'typescript':
      command = which.sync('tsc');
      args = [
        '--watch',
        '--out',
        options.output,
      ];
      break;

    case 'coffeescript':
      command = which.sync('coffee');
      args = [
        '--watch',
        '--compile',
        '--output',
        dirpath,
      ];
      break;

    case 'babel':
      command = which.sync('babel');
      args = [
        '--watch',
        '--out-file',
        options.output,
      ];
      break;
  }

  args = args.concat(options.args);

  var compiler = child.spawn(command, args);
  compiler.output = options.output;

  process.nextTick(function tick() {
    fs.exists(compiler.output, function(exists) {
      if (exists) {
        callback(null, compiler.stdout, compiler.stderr);
      } else {
        setTimeout(tick, 100);
      }
    });
  });

  return compiler;
}

function watch(options, callback) {
  var scripts = options.scripts || {};
  var cwd = options.cwd || process.cwd();

  var watcher = chokidar.watch(options.watch, {
    persistent: true
  });

  for (var name in scripts) {
    if (scripts.hasOwnProperty(name)) {
      var basename = path.basename(name);
      watcher.add(basename);
    }
  }

  var bugger = options.bugger;
  if (bugger) {
    var resolve = function(filename) {
      if (scripts[filename]) {
        return scripts[filename];
      }

    };

    var emit = function(event, filename) {
      var source = 'if (typeof(window) !== \'undefined\') {'
                 + '  var e = new CustomEvent(\''+ event + '\','
                 + '    { detail: \'' + filename +'\' });'
                 + ''
                 + '  window.dispatchEvent(e);'
                 + '}';
                 + ''
                 + 'if (typeof(process) !== \'undefined\') {'
                 + '  process.emit(\'' + event + '\', \'' + filename + '\');'
                 + '}';

      bugger.evaluate(source, function(error, result) {
        if (error) {
          bugger.emit('error', error);
        }
      });
    };

    watcher.on('add', function(filename) {
      var pathname = resolve(filename);
      emit('add', pathname);
    });

    watcher.on('remove', function(filename) {
      var pathname = resolve(filename);
      emit('remove', pathname);
    });

    watcher.on('change', function(filename) {
      var pathname = resolve(filename);
      emit('change', filename);

      bugger.scripts(function(scripts) {
        var script = scripts.filter(function(script) {
          var location = url.parse(script.url);
          return path.relative('/', location.path || '') === pathname;
        })[0];

        if (script === undefined) {
          return;
        }

        fs.readFile(filename, 'utf-8', function(error, contents) {
          if (error) {
            return bugger.emit('error', error);
          }

          bugger.source(script, contents);
        });
      });
    });

    bugger.on('source', function(script) {
      var location = url.parse(script.url);
      var pathname = path.relative('/', location.pathname || '');
      emit('source', pathname);
    });
  }

  if (callback) {
    watcher.once('ready', callback);
  }

  return watcher;
}

function debug(options, callback) {
  var bugger = rdbg.connect(options.debuggerPort, options.debuggerHost, function(target) {
    callback(null, target);
  });

  bugger.on('detatch', function() {
    var interval = setInterval(function() {
      bugger.targets(function(targets) {
        var target = targets.filter(function(target) {
          return target.url.search(options.url) > -1 && target.webSocketDebuggerUrl;
        })[0];

        if (target) {
          bugger.attach(target);
          clearInterval(interval);
        }
      });
    }, 250);
  });

  bugger.targets(function(targets) {
    var target = targets.filter(function(target) {
      return target.url.search(options.url) > -1 && target.webSocketDebuggerUrl;
    })[0];

    bugger.attach(target);
  });

  return bugger;
}

function open(options, callback) {
  var args = options.client.match(/'[^"]*'|"[^"]*"|\S+/g);
  var command = args.shift();

  switch (options.client) {
    case 'chrome':
      command = (function() {
        if (process.platform === 'win32') {
          var suffix = '\\Google\\Chrome\\Application\\chrome.exe';
          var prefixes = [
            process.env['LOCALAPPDATA'],
            process.env['PROGRAMFILES'],
            process.env['PROGRAMFILES(X86)'],
          ];

          var executables = prefixes.map(function(prefix) {
            return prefix + suffix;
          }).filter(function(path) {
            return fs.existsSync(path);
          });
          return executables[0];
        } else if (process.platform === 'darwin') {
          return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
        } else {
          return which.sync('google-chrome');
        }
      }());

      args = [
        '--remote-debugging-port=' + options.debuggerPort,
        '--no-first-run',
        '--no-default-browser-check',
        '--disable-translate',
        '--disable-default-apps',
        '--disable-popup-blocking',
        '--disable-zero-browsers-open-for-tests',
        '--user-data-dir=' + temp.mkdirSync('amok-chrome'),
      ];
      break;
  }

  args.push(options.url);

  var client = child.spawn(command, args);
  setTimeout(function() {
    callback(null, client.stdout, client.stderr);
  }, 1000);

  return client;
}

module.exports.serve = serve;
module.exports.watch = watch;
module.exports.compile = compile;
module.exports.debug = debug;
module.exports.open = open;
<|endoftext|>


<commit_before>var Client = require('castv2-client').Client;
var scanner = require('chromecast-scanner');
var ware = require('ware');
var mutate = require('mutate.js');
var inherits = require('util').inherits;
var ee = require('events').EventEmitter;
var extend = require('xtend');
var Promise = require('promiscuous');
var api = require('./api');
var noop = function() {};
var slice = Array.prototype.slice;

var defaults = {
  autoplay: true,
  ttl: 10000,
  startTime: 0,
  streamType: 'BUFFERED',
  activeTrackIds: [],
  media: {},
  cb: noop
};

var apirize = function(fn, ctx) {
  return mutate(function(opts) {
    opts = opts || {};
    if (opts._opts) {
        opts = extend(opts, opts._opts);
        delete opts._opts;
      }
      fn.call(ctx, opts);
    })
    .method(['function'], ['cb'])
    .method(['object', 'function'], ['_opts', 'cb'])
    .method(['string'], ['path'])
    .method(['string', 'function'], ['path', 'cb'])
    .method(['string', 'object'], ['path', '_opts'])
    .method(['string', 'object', 'function'], ['path', '_opts', 'cb'])
    .method(['string', 'string'], ['path', 'type'])
    .method(['string', 'string', 'function'], ['path', 'type', 'cb'])
    .method(['string', 'string', 'object'], ['path', 'type', '_opts'])
    .method(['string', 'string', 'object', 'function'], ['path', 'type', '_opts', 'cb'])
    .close();
};

var player = function() {
  if (!(this instanceof player)) return new player();
  ee.call(this);
  this.mw = ware();
  this.use = this.mw.use.bind(this.mw);

  this.launch = apirize(function(opts) {
    var that = this;
    var ctx = new ee();
    ctx.mode = 'launch';
    ctx.options = opts;
    ctx.api = api;
    this.mw.run(ctx, function(err, ctx) {
      ctx.options = extend(defaults, ctx.options);
      if (err) return ctx.options.cb(err);
      that._setStatus(ctx, 'loading plugins');
      that._scan(ctx)
        .then(function(ctx) { return that._connect(ctx); })
        .then(function(ctx) { return that._launch(ctx); })
        .then(function(ctx) { return that._load(ctx); })
        .then(function(ctx) { return that._status(ctx); })
        .then(function(ctx) { ctx.options.cb(null, ctx.player, ctx); },
              function(err) { ctx.options.cb(err); });
    });
  }, this);

  this.attach = apirize(function(opts) {
    var that = this;
    var ctx = new ee();
    ctx.mode = 'attach';
    ctx.options = opts;
    ctx.api = api;
    that._setStatus(ctx, 'loading plugins');
    this.mw.run(ctx, function(err, opts) {
      ctx.options = extend(defaults, ctx.options);
      if (err) return options.cb(err);
      that._scan(ctx)
        .then(function(ctx) { return that._connect(ctx); })
        .then(function(ctx) { return that._find(ctx); })
        .then(function(ctx) { return that._join(ctx); })
        .then(function(ctx) { return that._status(ctx); })
        .then(function(ctx) { ctx.options.cb(null, ctx.player, ctx); },
              function(err) { ctx.options.cb(err); });
    });
  }, this);
};

inherits(player, ee);

// find chromecast devices in the network and
// either return the first found or the one
// which matches device.
player.prototype._scan = function(ctx) {
  this._setStatus(ctx, 'scanning');
  return new Promise(function(resolve, reject) {
    if (ctx.options.address) {
      ctx.address = ctx.options.address;
      return resolve(ctx);
    }
    scanner({ device: ctx.options.device, ttl: ctx.options.ttl },
      function(err, service) {
        if (err) return reject(err);
        ctx.address = service.address;
        resolve(ctx);
      }
    );
  });
};

// establish a connection to a chromecast device
player.prototype._connect = function(ctx) {
  this._setStatus(ctx, 'connecting');
  return new Promise(function(resolve, reject) {
    var client = new Client();
    client.connect(ctx.address, function() {
      ctx.client = client;
      resolve(ctx);
    });
    client.on('error', function() {
      client.close();
    });
  });
};

// find running app
player.prototype._find = function(ctx) {
  this._setStatus(ctx, 'finding');
  return new Promise(function(resolve, reject) {
    ctx.client.getSessions(function(err, apps) {
      if (err) return reject(err);
      if (!apps.length) return reject(new Error('app not found'));
      ctx.session = apps[0];
      resolve(ctx);
    });
  });
};

// join an existing chromecast session
player.prototype._join = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'joining');
  return new Promise(function(resolve, reject) {
    ctx.client.join(ctx.session, ctx.api,
      function(err, p) {
        if (err) return reject(err);
        that._setStatus(ctx, 'ready');
        ctx.player = p;
        resolve(ctx);
      }
    );
  });
};

// fetch the current state of the player
player.prototype._status = function(ctx) {
  return new Promise(function(resolve, reject) {
    ctx.player.getStatus(function(err) {
      if (err) return reject(err);
      resolve(ctx);
    });
  });
};

// launch an application
player.prototype._launch = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'launching');
  return new Promise(function(resolve, reject) {
    ctx.client.launch(ctx.api, function(err, p) {
      if (err) return reject(err);
      ctx.player = p;
      ctx.player.on('status', function(status) {
        that._setStatus(ctx, status.playerState.toLowerCase());
      });
      resolve(ctx);
    });
  });
};

// load a media file
player.prototype._load = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'loading');
  return new Promise(function(resolve, reject) {
    ctx.player.load(ctx.options, function(err) {
      if (err) return reject(err);
      that._setStatus(ctx, 'ready');
      ctx.player.on('status', function(status) {
        that._setStatus(ctx, status.playerState.toLowerCase());
      });
      resolve(ctx);
    });
  });
};

player.prototype._setStatus = function(ctx, status) {
  ctx.status = status;
  ctx.emit('status', status);
};

player.api = api;

module.exports = player;
<commit_msg>..status<commit_after>var Client = require('castv2-client').Client;
var scanner = require('chromecast-scanner');
var ware = require('ware');
var mutate = require('mutate.js');
var inherits = require('util').inherits;
var ee = require('events').EventEmitter;
var extend = require('xtend');
var Promise = require('promiscuous');
var api = require('./api');
var noop = function() {};
var slice = Array.prototype.slice;

var defaults = {
  autoplay: true,
  ttl: 10000,
  startTime: 0,
  streamType: 'BUFFERED',
  activeTrackIds: [],
  media: {},
  cb: noop
};

var apirize = function(fn, ctx) {
  return mutate(function(opts) {
    opts = opts || {};
    if (opts._opts) {
        opts = extend(opts, opts._opts);
        delete opts._opts;
      }
      fn.call(ctx, opts);
    })
    .method(['function'], ['cb'])
    .method(['object', 'function'], ['_opts', 'cb'])
    .method(['string'], ['path'])
    .method(['string', 'function'], ['path', 'cb'])
    .method(['string', 'object'], ['path', '_opts'])
    .method(['string', 'object', 'function'], ['path', '_opts', 'cb'])
    .method(['string', 'string'], ['path', 'type'])
    .method(['string', 'string', 'function'], ['path', 'type', 'cb'])
    .method(['string', 'string', 'object'], ['path', 'type', '_opts'])
    .method(['string', 'string', 'object', 'function'], ['path', 'type', '_opts', 'cb'])
    .close();
};

var player = function() {
  if (!(this instanceof player)) return new player();
  ee.call(this);
  this.mw = ware();
  this.use = this.mw.use.bind(this.mw);

  this.launch = apirize(function(opts) {
    var that = this;
    var ctx = new ee();
    ctx.mode = 'launch';
    ctx.options = opts;
    ctx.api = api;
    this.mw.run(ctx, function(err, ctx) {
      ctx.options = extend(defaults, ctx.options);
      if (err) return ctx.options.cb(err);
      that._setStatus(ctx, 'loading plugins');
      that._scan(ctx)
        .then(function(ctx) { return that._connect(ctx); })
        .then(function(ctx) { return that._launch(ctx); })
        .then(function(ctx) { return that._load(ctx); })
        .then(function(ctx) { return that._status(ctx); })
        .then(function(ctx) { ctx.options.cb(null, ctx.player, ctx); },
              function(err) { ctx.options.cb(err); });
    });
  }, this);

  this.attach = apirize(function(opts) {
    var that = this;
    var ctx = new ee();
    ctx.mode = 'attach';
    ctx.options = opts;
    ctx.api = api;
    that._setStatus(ctx, 'loading plugins');
    this.mw.run(ctx, function(err, opts) {
      ctx.options = extend(defaults, ctx.options);
      if (err) return options.cb(err);
      that._scan(ctx)
        .then(function(ctx) { return that._connect(ctx); })
        .then(function(ctx) { return that._find(ctx); })
        .then(function(ctx) { return that._join(ctx); })
        .then(function(ctx) { return that._status(ctx); })
        .then(function(ctx) { ctx.options.cb(null, ctx.player, ctx); },
              function(err) { ctx.options.cb(err); });
    });
  }, this);
};

inherits(player, ee);

// find chromecast devices in the network and
// either return the first found or the one
// which matches device.
player.prototype._scan = function(ctx) {
  this._setStatus(ctx, 'scanning');
  return new Promise(function(resolve, reject) {
    if (ctx.options.address) {
      ctx.address = ctx.options.address;
      return resolve(ctx);
    }
    scanner({ device: ctx.options.device, ttl: ctx.options.ttl },
      function(err, service) {
        if (err) return reject(err);
        ctx.address = service.address;
        resolve(ctx);
      }
    );
  });
};

// establish a connection to a chromecast device
player.prototype._connect = function(ctx) {
  this._setStatus(ctx, 'connecting');
  return new Promise(function(resolve, reject) {
    var client = new Client();
    client.connect(ctx.address, function() {
      ctx.client = client;
      resolve(ctx);
    });
    client.on('error', function() {
      client.close();
    });
  });
};

// find running app
player.prototype._find = function(ctx) {
  this._setStatus(ctx, 'finding');
  return new Promise(function(resolve, reject) {
    ctx.client.getSessions(function(err, apps) {
      if (err) return reject(err);
      if (!apps.length) return reject(new Error('app not found'));
      ctx.session = apps[0];
      resolve(ctx);
    });
  });
};

// join an existing chromecast session
player.prototype._join = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'joining');
  return new Promise(function(resolve, reject) {
    ctx.client.join(ctx.session, ctx.api,
      function(err, p) {
        if (err) return reject(err);
        that._setStatus(ctx, 'ready');
        ctx.player = p;
        ctx.player.on('status', function(status) {
          that._setStatus(ctx, status.playerState.toLowerCase());
        });
        resolve(ctx);
      }
    );
  });
};

// fetch the current state of the player
player.prototype._status = function(ctx) {
  return new Promise(function(resolve, reject) {
    ctx.player.getStatus(function(err) {
      if (err) return reject(err);
      resolve(ctx);
    });
  });
};

// launch an application
player.prototype._launch = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'launching');
  return new Promise(function(resolve, reject) {
    ctx.client.launch(ctx.api, function(err, p) {
      if (err) return reject(err);
      ctx.player = p;
      resolve(ctx);
    });
  });
};

// load a media file
player.prototype._load = function(ctx) {
  var that = this;
  this._setStatus(ctx, 'loading');
  return new Promise(function(resolve, reject) {
    ctx.player.load(ctx.options, function(err) {
      if (err) return reject(err);
      that._setStatus(ctx, 'ready');
      ctx.player.on('status', function(status) {
        that._setStatus(ctx, status.playerState.toLowerCase());
      });
      resolve(ctx);
    });
  });
};

player.prototype._setStatus = function(ctx, status) {
  ctx.status = status;
  ctx.emit('status', status);
};

player.api = api;

module.exports = player;
<|endoftext|>


<commit_before>const pathtoregexp = require('path-to-regexp')

const route = () => {
  let _routes = []
  const res = (pattern, callback, options) => {
    if (callback != null) {
      if (pattern === '*') pattern = '(.*)'
      const entry = {
        pattern: pattern,
        match: pathtoregexp(pattern, options),
        cb: callback
      }
      _routes.push(entry)
      return {
        off: () => {
          const index = _routes.indexOf(entry)
          if (index != -1) _routes.splice(index, 1)
        }
      }
    }
    const qindex = pattern.indexOf('?')
    if (qindex !== -1) pattern = pattern.slice(0, qindex)
    for (let r of _routes) {
      const result = r.match.exec(decodeURIComponent(pattern))
      if (result == null) continue
      const params = {}
      r.match.keys.forEach((key, i) => {
        const val = decodeURIComponent(result[i + 1].replace(/\+/g, ' '))
        if (val == null && !hasOwnProperty.call(params, key.name)) return
        params[key.name] = val
      })
      return r.cb({
        url: pattern,
        params: params
      })
    }
    throw new Error('no route found')
  }
  res.routes = () => _routes
  res.clearAll = () => {
    _routes = []
  }
  return res
}

let globalroute = null

const globalapi = (pattern, callback, options) => {
  if (pattern == null) return route()
  if (globalroute == null) globalroute = route()
  return globalroute(pattern, callback, options)
}

globalapi.routes = () => {
  if (globalroute == null) globalroute = route()
  return globalroute.routes()
}

globalapi.clearAll = () => {
  if (globalroute == null) globalroute = route()
  globalroute.clearAll()
}

module.exports = globalapi
<commit_msg>nicer api<commit_after>const pathtoregexp = require('path-to-regexp')

const route = () => {
  let routes = []
  const res = (pattern, callback, options) => {
    if (callback != null) {
      if (pattern === '*') pattern = '(.*)'
      const entry = {
        pattern: pattern,
        match: pathtoregexp(pattern, options),
        cb: callback
      }
      routes.push(entry)
      return {
        off: () => {
          const index = routes.indexOf(entry)
          if (index != -1) routes.splice(index, 1)
        }
      }
    }
    const qindex = pattern.indexOf('?')
    if (qindex !== -1) pattern = pattern.slice(0, qindex)
    for (let r of routes) {
      const result = r.match.exec(decodeURIComponent(pattern))
      if (result == null) continue
      const params = {}
      r.match.keys.forEach((key, i) => {
        const val = decodeURIComponent(result[i + 1].replace(/\+/g, ' '))
        if (val == null && !hasOwnProperty.call(params, key.name)) return
        params[key.name] = val
      })
      return r.cb({
        url: pattern,
        params: params
      })
    }
    throw new Error('no route found')
  }
  res.routes = () => routes
  res.clearAll = () => {
    routes = []
  }
  return res
}

let _route = null
const assert = () => {
  if (_route == null) _route = route()
  return _route
}

module.exports = (pattern, callback, options) => {
  if (pattern == null) return route()
  return assert()(pattern, callback, options)
}
module.exports.routes = () => assert().routes()
module.exports.clearAll = () => assert().clearAll()
<|endoftext|>


<commit_before>var tile = function() {
  var size = [960, 500],
      scale = 256,
      translate = [size[0] / 2, size[1] / 2],
      zoomDelta = 0;

  function tile() {
    var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
        z0 = Math.round(z + zoomDelta),
        k = Math.pow(2, z - z0 + 8),
        origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
        tiles = [],
        cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
        rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));

    rows.forEach(function(y) {
      cols.forEach(function(x) {
        tiles.push([x, y, z0]);
      });
    });

    tiles.translate = origin;
    tiles.scale = k;

    return tiles;
  }

  tile.size = function(_) {
    if (!arguments.length) return size;
    size = _;
    return tile;
  };

  tile.scale = function(_) {
    if (!arguments.length) return scale;
    scale = _;
    return tile;
  };

  tile.translate = function(_) {
    if (!arguments.length) return translate;
    translate = _;
    return tile;
  };

  tile.zoomDelta = function(_) {
    if (!arguments.length) return zoomDelta;
    zoomDelta = +_;
    return tile;
  };

  return tile;
};

// Utility functions
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#ECMAScript_.28JavaScript.2FActionScript.2C_etc..29

// coords -> tile
function long2tile(lon, zoom) {
  return (Math.floor((lon+180)/360*Math.pow(2,zoom)));
}

function lat2tile(lat, zoom)  {
  return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)));
}

// tile -> bounding box
function tile2long(x, z) {
 return (x/Math.pow(2,z)*360-180);
}

function tile2lat(y, z) {
 var n = Math.PI-2*Math.PI*y/Math.pow(2,z);
 return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
}

tile.locationToTile = function(lat, lon, zoom) {
  return {
    x: long2tile(lon, zoom),
    y: lat2tile(lon, zoom),
    z: zoom
  };
};

tile.tileToBoundingBox = function(x, y, z) {
  return [
    [tile2long(x, z), tile2lat(y, z)],
    [tile2long(x, z), tile2lat(y, z)]
  ];
};

module.exports = tile;<commit_msg>fixed an error in tileToBoundingBox<commit_after>var tile = function() {
  var size = [960, 500],
      scale = 256,
      translate = [size[0] / 2, size[1] / 2],
      zoomDelta = 0;

  function tile() {
    var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
        z0 = Math.round(z + zoomDelta),
        k = Math.pow(2, z - z0 + 8),
        origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
        tiles = [],
        cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
        rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));

    rows.forEach(function(y) {
      cols.forEach(function(x) {
        tiles.push([x, y, z0]);
      });
    });

    tiles.translate = origin;
    tiles.scale = k;

    return tiles;
  }

  tile.size = function(_) {
    if (!arguments.length) return size;
    size = _;
    return tile;
  };

  tile.scale = function(_) {
    if (!arguments.length) return scale;
    scale = _;
    return tile;
  };

  tile.translate = function(_) {
    if (!arguments.length) return translate;
    translate = _;
    return tile;
  };

  tile.zoomDelta = function(_) {
    if (!arguments.length) return zoomDelta;
    zoomDelta = +_;
    return tile;
  };

  return tile;
};

// Utility functions
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#ECMAScript_.28JavaScript.2FActionScript.2C_etc..29

// coords -> tile
function long2tile(lon, zoom) {
  return (Math.floor((lon+180)/360*Math.pow(2,zoom)));
}

function lat2tile(lat, zoom)  {
  return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)));
}

// tile -> bounding box
function tile2long(x, z) {
 return (x/Math.pow(2,z)*360-180);
}

function tile2lat(y, z) {
 var n = Math.PI-2*Math.PI*y/Math.pow(2,z);
 return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
}

tile.locationToTile = function(lat, lon, zoom) {
  return {
    x: long2tile(lon, zoom),
    y: lat2tile(lon, zoom),
    z: zoom
  };
};

tile.tileToBoundingBox = function(x, y, z) {
  return [
    [tile2long(x, z), tile2lat(y, z)],
    [tile2long(x + 1, z), tile2lat(y + 1, z)]
  ];
};

module.exports = tile;<|endoftext|>