<commit_before>'use strict';

var util = require('./lib/util');

exports = module.exports = Mase;

/**
### README

The module exports a constructor.

```js
var Mase = require('mase');
var db = new Mase(string name, array data)
```

Memory dbs with the same `name` share memory.
It can take an array of `data` as a second or first argument.
If so, `data` is upserted into the db by only using each
document's `_id` as a selector.

### spec
```js
function Mase([string name, array data])
```

_arguments_
- `name` type string, name for the collection
- `data` type array to insert in memory db

_defaults_
- `name` to a random 24 length string using `[A-Za-z0-9]` characters
- `data`
  - to the previous collection `name` array if there was one
  - to empty array if collection `name` it wasn't

_returns_ a new instance

_instance properties_
- `store` array of data of the instance

**/

// dbs namespace
var mase = {};

function Mase(name, data){
  if(!(this instanceof Mase)){
    return new Mase(name, data);
  }

  data = data || name;
  this.name = util.type(name).string || util.randomID();
  if(mase[this.name]){ return mase[this.name]; }

  this.store = [];
  mase[this.name] = this;

  if(util.type(data).array){
    data.forEach(function(item){
      this.update({_id: item._id}, item, {$upsert: true});
    }, this);
  }
}

/**
## insert

Insert a new document. When `document` is not a plain object,
i.e. `'one', 1, etc.`, it will be inserted using its value.

```js
db.insert(1); // => {value: 1, _id: 'wZy7rd33Q8478pvi'}
```

### spec
```js
function insert(object|any document)
```

_arguments_
 - `document` type object or any, element to insert.

_defaults_
 - `document._id` to a 24 length random string

_returns_ a clone of the inserted `document`

**/
Mase.prototype.insert = function(_doc){
  var doc = util.clone(util.type(_doc).plainObject || {value: _doc}, true);
  if(doc._id === void 0){ doc._id = util.randomID(); }
  this.changed('insert', doc, null);
  this.store.push(doc);
  return doc;
};

/**
## find

Find documents. By default, documents are tested
for value equality with [`lodash.isEqual`][p-lodash.isEqual].
This can be changed using a `$test` function.

### spec
```js
function find([object fields, object options|function $test])
```

_arguments_
 - `fields` type object, document fields for lookup
 - `$test` type function that will test `fields` for each document
 - `options` type object, helper object on how to do the lookup

_options_ properties
 - `$acc` type boolean, return value of the `$test` function
 - `$test` type function that tests `fields` against each document
 - `$break` type boolean, wether to **break the search after a match**
 - `$count` type boolean, wether to have `result` start as `0` or `[]`
 - `$result` type array or number, result returned. It will start as:
  - empty array when `$count` is falsy
  - `0` when `$count` is truthy

`$test(fields, doc, key, options)` _arguments_
 - `fields` object fields given as argument
 - `doc` document object found
 - `key` property of `fields` to be tested
 - `options` the options object passed in to `find`

_defaults_
- `options.$test` an equality test using [`lodash.isEqual`][p-lodash.isEqual]

_returns_ `o.$result`

[p-lodash.isEqual]: https://lodash.com/docs#isEqual
**/
Mase.prototype.find = function(fields, o){
  if(fields && !util.type(fields).match(/function|plainObject/)){
    throw new TypeError('find([fields, object options|function $test]) '
      + '`fields` should be function or plainObject'
    );
  }

  var spec = Object.keys(fields || {});
  var length = this.store.length;
  o = util.type(o).plainObject || {$test: o || fields};

  if(!spec.length){ spec = null; }
  if(!length || (!spec && typeof o.$test !== 'function')){
    return o.$count ? length : util.clone(this.store, true);
  }

  if(typeof o.$test !== 'function'){
    o.$test = util.test.$equal;
  }

  if(typeof o.$match !== 'function'){
    o.$match = (o.$count && util.match.$count) || util.match.$equal;
  }

  --length;
  o.$result = o.$count ? 0 : [];
  var index = -1, store = this.store;
  // ^ better than index < length-1 in `whilst`

  o.$count = 0;
  (function whilst(){
    o.$acc = true;
    var doc = store[++index];
    var match = (spec || Object.keys(doc)).filter(function(key){
      return (o.$acc = o.$test(fields, doc, key, o));
    }).length;

    if(match){
      ++o.$count;
      o.$match(doc, o);
      if(o.$break){ return ; }
    }
    if(index < length){ whilst(); }
  })();

  if(o.$ref){ return o.$result; }
  return util.clone(o.$result, true);
};

/**
## findOne

This method is just sugar on top of `find` enforcing
it to always return an object or null if nothing was found.

```js
var foundOne = find(fields, {
  $test: [Function] // if given
  $break: true,
  $count: false
})[0];
```

### spec
```js
function findOne(fields[, options|function $test])
```

Same as [`find`'s spec](./find.md#spec), differences below

_options_ properties
 - `$count` is always set to `false`
 - `$break` is always set to `true`

_returns_
 - the object document if found
 - `null` otherwise

**/

Mase.prototype.findOne = function(fields, o){
  o = util.type(o).plainObject || {$test: o};

  o.$break = true;
  o.$count = false;

  return this.find(fields, o)[0] || null;
};

/**
## update

Update/Upsert documents in the memory db. They are found first using
 `find` and then updated. Documents updates can be customized
 by using an `$update` function.

### spec
```js
function update(
  object fields,
  [object update|function $update],
  [object options|function $update]
)
```

_arguments_
 - `fields` type object, document(s) fields to lookup
 - `update` type object, which fields to update on document(s) found
 - `$update` type function, customizes how to update fields
 - `options` type object, modifies how to do the update

_options_. Same they are for [`find`](./find.md) plus
 - `$upsert` type boolean, wether to `insert` if no documents found
 - `$update` type function, customizer for the update

`$update(doc, update)` _arguments_
 - `doc` document found using `fields`
 - `update` same object given as argument

_defaults_
- `options.$update` to merge properties of `doc` with `update`

_returns_ `this`

**/
Mase.prototype.update = function(fields, update, o){
  if(
    !util.type(fields).plainObject &&
    !util.type(update).match(/function|plainObject/)
  ){
    throw new TypeError('update(fields, update[, options])\n'
      + ' `fields` should be plainObject\n'
      + ' `update` should be function or plainObject'
    );
  }

  if(update.$update){ o = update; }
  o = util.type(o).plainObject || {$update: o || update};

  if(typeof o.$update !== 'function'){
    o.$update = util.merge;
  }

  o.$ref = true; o.$count = false;
  var found = this.find(fields, o).map(function(doc){
    this.changed('update', update, doc);
    o.$update(doc, update);
    return doc;
  }, this);

  if(!found.length && o.$upsert){
    this.insert(o.$update(fields, update));
  }

  return this;
};

/**
## remove

```js
function remove(any id)
```
Remove only one document at a time.

_arguments_
 - `id` type any, id of the document to delete

_returns_
 - `true` if there was a document removed
 - `false` if there was no document removed

**/
Mase.prototype.remove = function(_id){
  var index = 0, length = this.store.length;

  if(!_id && _id !== 0){
    this.changed('remove', null, this.store);
    this.store = [];
    return Boolean(length);
  }

  var self = this;
  (function whilst(){
    if(util.isEqual(_id, self.store[index]._id)){
      self.changed('remove', null, self.store[index]);
      self.store.splice(index, 1);
      index += length + 1;
    }
    if(++index < length){ whilst(); }
  })();

  return index > length;
};

/**
## changed

Function called before any `insert`, `update` and `remove` .
Should be set manually since its only stored on the `prototype`
and or your instance.

```js
var db = new Mase('name', [1,2,3]);

db.changed = function(method, newDoc, oldDoc){
  switch(method){
    case 'insert':
      // call your websockets, etc.
    break;
    // etc
    default:
      return ;
    break;
  }
}
```

The `oldDoc` and `newDoc` are passed just before the change is done
 so beware to not mutate them. If you pass them to another function on the
 same process I would highly-super-obnoxiously tell you to clone them.
 If you are using this as is plotted above (for websocket action, etc.)
 it would be fine.

### spec

```js
function changed(string method, object newDoc, object oldDoc)
```

_arguments_
 - `method` type string, method that maked the change
 - `newDoc` type object, change performed on document
 - `oldDoc` type object, document to be changed

**/
Mase.prototype.changed = function onChange(){ /* empty */ };
<commit_msg>refactor: simplifying find to be faster<commit_after>'use strict';

var util = require('./lib/util');

exports = module.exports = Mase;

/**
### README

The module exports a constructor.

```js
var Mase = require('mase');
var db = new Mase(string name, array data)
```

Memory dbs with the same `name` share memory.
It can take an array of `data` as a second or first argument.
If so, `data` is upserted into the db by only using each
document's `_id` as a selector.

### spec
```js
function Mase([string name, array data])
```

_arguments_
- `name` type string, name for the collection
- `data` type array to insert in memory db

_defaults_
- `name` to a random 24 length string using `[A-Za-z0-9]` characters
- `data`
  - to the previous collection `name` array if there was one
  - to empty array if collection `name` it wasn't

_returns_ a new instance

_instance properties_
- `store` array of data of the instance

**/

// dbs namespace
var mase = {};

function Mase(name, data){
  if(!(this instanceof Mase)){
    return new Mase(name, data);
  }

  data = data || name;
  this.name = util.type(name).string || util.randomID();
  if(mase[this.name]){ return mase[this.name]; }

  this.store = [];
  mase[this.name] = this;

  if(util.type(data).array){
    data.forEach(function(item){
      this.update({_id: item._id}, item, {$upsert: true});
    }, this);
  }
}

/**
## insert

Insert a new document. When `document` is not a plain object,
i.e. `'one', 1, etc.`, it will be inserted using its value.

```js
db.insert(1); // => {value: 1, _id: 'wZy7rd33Q8478pvi'}
```

### spec
```js
function insert(object|any document)
```

_arguments_
 - `document` type object or any, element to insert.

_defaults_
 - `document._id` to a 24 length random string

_returns_ a clone of the inserted `document`

**/
Mase.prototype.insert = function(_doc){
  var doc = util.clone(util.type(_doc).plainObject || {value: _doc}, true);
  if(doc._id === void 0){ doc._id = util.randomID(); }
  this.changed('insert', doc, null);
  this.store.push(doc);
  return doc;
};

/**
## find

Find documents. By default, documents are tested
for value equality with [`lodash.isEqual`][p-lodash.isEqual].
This can be changed using a `$test` function.

### spec
```js
function find([object fields, object options|function $test])
```

_arguments_
 - `fields` type object, document fields for lookup
 - `$test` type function that will test `fields` for each document
 - `options` type object, helper object on how to do the lookup

_options_ properties
 - `$acc` type boolean, return value of the `$test` function
 - `$test` type function that tests `fields` against each document
 - `$break` type boolean, wether to **break the search after a match**
 - `$count` type boolean, wether to have `result` start as `0` or `[]`
 - `$result` type array or number, result returned. It will start as:
  - empty array when `$count` is falsy
  - `0` when `$count` is truthy

`$test(fields, doc, key, options)` _arguments_
 - `fields` object fields given as argument
 - `doc` document object found
 - `key` property of `fields` to be tested
 - `options` the options object passed in to `find`

_defaults_
- `options.$test` an equality test using [`lodash.isEqual`][p-lodash.isEqual]

_returns_ `o.$result`

[p-lodash.isEqual]: https://lodash.com/docs#isEqual
**/
Mase.prototype.find = function(fields, o){
  try { var spec = typeof fields === 'object' && Object.keys(fields); }
  catch(err){
    throw new TypeError('find([fields, object|function options]) '
      + '1st argument should be function or plainObject'
    );
  }

  o = (typeof o === 'object' && o) || {$test: o || fields};
  if(typeof o.$test !== 'function'){ o.$test = util.$test; }

  var index = -1;
  var store = this.store;
  var length = store.length;

  function search(){
    var doc = store[++index];
    if(o.$test(fields, doc, spec, o)){
      o.$result.push(doc);
      if(o.$break){ return ; }
    }
    if(index < length){ search(); }
  }

  if(!length || (!spec && typeof o.$test !== 'function')){
    o.$result = this.store;
  } else {
    --length; // <- better than index < length-1 whilst search
    o.$result = []; search();
  }

  if(o.$ref){ return o.$result; }
  return util.clone(o.$result, true);
};

/**
## findOne

This method is just sugar on top of `find` enforcing
it to always return an object or null if nothing was found.

```js
var foundOne = find(fields, {
  $test: [Function] // if given
  $break: true,
  $count: false
})[0];
```

### spec
```js
function findOne(fields[, options|function $test])
```

Same as [`find`'s spec](./find.md#spec), differences below

_options_ properties
 - `$count` is always set to `false`
 - `$break` is always set to `true`

_returns_
 - the object document if found
 - `null` otherwise

**/

Mase.prototype.findOne = function(fields, o){
  o = util.type(o).plainObject || {$test: o};

  o.$break = true;
  o.$count = false;

  return this.find(fields, o)[0] || null;
};

/**
## update

Update/Upsert documents in the memory db. They are found first using
 `find` and then updated. Documents updates can be customized
 by using an `$update` function.

### spec
```js
function update(
  object fields,
  [object update|function $update],
  [object options|function $update]
)
```

_arguments_
 - `fields` type object, document(s) fields to lookup
 - `update` type object, which fields to update on document(s) found
 - `$update` type function, customizes how to update fields
 - `options` type object, modifies how to do the update

_options_. Same they are for [`find`](./find.md) plus
 - `$upsert` type boolean, wether to `insert` if no documents found
 - `$update` type function, customizer for the update

`$update(doc, update)` _arguments_
 - `doc` document found using `fields`
 - `update` same object given as argument

_defaults_
- `options.$update` to merge properties of `doc` with `update`

_returns_ `this`

**/
Mase.prototype.update = function(fields, update, o){
  if(
    !util.type(fields).plainObject &&
    !util.type(update).match(/function|plainObject/)
  ){
    throw new TypeError('update(fields, update[, options])\n'
      + ' `fields` should be plainObject\n'
      + ' `update` should be function or plainObject'
    );
  }

  if(update.$update){ o = update; }
  o = util.type(o).plainObject || {$update: o || update};

  if(typeof o.$update !== 'function'){
    o.$update = util.merge;
  }

  o.$ref = true; o.$count = false;
  var found = this.find(fields, o).map(function(doc){
    this.changed('update', update, doc);
    o.$update(doc, update);
    return doc;
  }, this);

  if(!found.length && o.$upsert){
    this.insert(o.$update(fields, update));
  }

  return this;
};

/**
## remove

```js
function remove(any id)
```
Remove only one document at a time.

_arguments_
 - `id` type any, id of the document to delete

_returns_
 - `true` if there was a document removed
 - `false` if there was no document removed

**/
Mase.prototype.remove = function(_id){
  var index = 0, length = this.store.length;

  if(!_id && _id !== 0){
    this.changed('remove', null, this.store);
    this.store = [];
    return Boolean(length);
  }

  var self = this;
  (function whilst(){
    if(util.isEqual(_id, self.store[index]._id)){
      self.changed('remove', null, self.store[index]);
      self.store.splice(index, 1);
      index += length + 1;
    }
    if(++index < length){ whilst(); }
  })();

  return index > length;
};

/**
## changed

Function called before any `insert`, `update` and `remove` .
Should be set manually since its only stored on the `prototype`
and or your instance.

```js
var db = new Mase('name', [1,2,3]);

db.changed = function(method, newDoc, oldDoc){
  switch(method){
    case 'insert':
      // call your websockets, etc.
    break;
    // etc
    default:
      return ;
    break;
  }
}
```

The `oldDoc` and `newDoc` are passed just before the change is done
 so beware to not mutate them. If you pass them to another function on the
 same process I would highly-super-obnoxiously tell you to clone them.
 If you are using this as is plotted above (for websocket action, etc.)
 it would be fine.

### spec

```js
function changed(string method, object newDoc, object oldDoc)
```

_arguments_
 - `method` type string, method that maked the change
 - `newDoc` type object, change performed on document
 - `oldDoc` type object, document to be changed

**/
Mase.prototype.changed = function onChange(){ /* empty */ };
<|endoftext|>


<commit_before>var _ = require('underscore');
var fs = require('fs');
var path = require('path');

module.exports = (function() {
    var noIndex = function(str) {
        return String(str).replace(path.sep, '/', 'g').replace(/\/index$/, '/').toLowerCase();
    };

    var noSlash = function(str) {
        return String(str).replace(path.sep, '/', 'g').replace(/\/+$/, '');
    };

    var trailingSlash  = function(str) {
        return noSlash(str) + '/';
    };

    var defaultDelegate = function(path, filename){
        return filename[0] !== '.' && /\.(js|coffee)$/i.test(filename);
    };

    // FIXME: support *
    var methods = ['get', 'post', 'put', 'delete', 'options'];

    var doMergeRoute = function(existingRoutes, routeModule, routeUrl) {
        var name = noSlash(noIndex(routeUrl)) || '/';
        var r = existingRoutes[name] || {};
        var s = {};

        _.each(routeModule, function(value, key) {
            if (methods.indexOf(key) > -1) {
                r[key] = value;
            } else {
                s[key] = value;
            }
        });

        _.each(s, function(value, key) {
            doMergeRoute(existingRoutes, value, path.join(name, key));
        });

        console.log('domergeRoute', routeUrl, existingRoutes, r, s);

        existingRoutes[name] = r;
    };

    var mergeRoute = function(existingRoutes, routePath, routeUrl) {
        var mod = require(routePath);

        doMergeRoute(existingRoutes, mod, routeUrl);
    };

    var getRoutes = function(module, /*optional*/dir, /*optional*/urlPrefix, /*optional*/existingRoutes) {
        var result = existingRoutes || {};
        var subdirs = [];

        dir = trailingSlash(dir || 'routes');
        urlPrefix = trailingSlash(urlPrefix || '');

        var baseDir = path.dirname(module.filename);
        var routeDir = path.join(baseDir, dir);

        fs.readdirSync(routeDir).forEach(function(filename) {
            var name = filename.substring(0, filename.lastIndexOf('.'));
            var joined = path.join(routeDir, filename);

            // console.log('joined', name, filename, joined);

            if (fs.statSync(joined).isDirectory()) {
                subdirs.push({dir: path.join(dir, filename), url: path.join(urlPrefix, filename)});
            } else if (defaultDelegate(joined, filename)) {
                mergeRoute(result, joined, [urlPrefix, name].join(''));
            }
        });

        subdirs.forEach(function(folder) {
            getRoutes(module, folder.dir, folder.url, result);
        });

        return result;
    };

    var	installRoutes = function(module, app, /*optional*/dir, /*optional*/urlPrefix) {
        var routes = getRoutes(module, dir, urlPrefix);

        _.each(routes, function(value, key) {
            _.each(value, function(handler, method) {
                console.log('registering ' + method + ' handler for ' + key, handler);
                app[method](key, handler);
            });
        });

        return routes;
    };

    return {get: getRoutes, install: installRoutes};
}());<commit_msg>Actually add the windows compatibility code *sigh*<commit_after>var _ = require('underscore');
var fs = require('fs');
var path = require('path');

module.exports = (function() {
    var makeUrl = function(str) {
        if (path.sep == '/') {
            return String(str);
        }

        return String(str).replace(path.sep, '/', 'g').replace(path.sep, '/', 'g');
    };

    var noIndex = function(str) {
        return makeUrl(str).replace(/\/index$/, '/').toLowerCase();
    };

    var noSlash = function(str) {
        return makeUrl(str).replace(/\/+$/, '');
    };

    var trailingSlash  = function(str) {
        return noSlash(str) + '/';
    };

    var defaultDelegate = function(path, filename){
        return filename[0] !== '.' && /\.(js|coffee)$/i.test(filename);
    };

    // FIXME: support *
    var methods = ['get', 'post', 'put', 'delete', 'options'];

    var doMergeRoute = function(existingRoutes, routeModule, routeUrl) {
        var name = noSlash(noIndex(routeUrl)) || '/';
        var r = existingRoutes[name] || {};
        var s = {};

        _.each(routeModule, function(value, key) {
            if (methods.indexOf(key) > -1) {
                r[key] = value;
            } else {
                s[key] = value;
            }
        });

        _.each(s, function(value, key) {
            doMergeRoute(existingRoutes, value, path.join(name, key));
        });

        //console.log('domergeRoute', routeUrl, name, r, s);

        existingRoutes[name] = r;
    };

    var mergeRoute = function(existingRoutes, routePath, routeUrl) {
        var mod = require(routePath);

        doMergeRoute(existingRoutes, mod, routeUrl);
    };

    var getRoutes = function(module, /*optional*/dir, /*optional*/urlPrefix, /*optional*/existingRoutes) {
        var result = existingRoutes || {};
        var subdirs = [];

        dir = trailingSlash(dir || 'routes');
        urlPrefix = trailingSlash(urlPrefix || '');

        var baseDir = path.dirname(module.filename);
        var routeDir = path.join(baseDir, dir);

        fs.readdirSync(routeDir).forEach(function(filename) {
            var name = filename.substring(0, filename.lastIndexOf('.'));
            var joined = path.join(routeDir, filename);

            // console.log('joined', name, filename, joined);

            if (fs.statSync(joined).isDirectory()) {
                subdirs.push({dir: path.join(dir, filename), url: path.join(urlPrefix, filename)});
            } else if (defaultDelegate(joined, filename)) {
                mergeRoute(result, joined, [urlPrefix, name].join(''));
            }
        });

        subdirs.forEach(function(folder) {
            getRoutes(module, folder.dir, folder.url, result);
        });

        return result;
    };

    var	installRoutes = function(module, app, /*optional*/dir, /*optional*/urlPrefix) {
        var routes = getRoutes(module, dir, urlPrefix);

        _.each(routes, function(value, key) {
            _.each(value, function(handler, method) {
                console.log('registering ' + method + ' handler for ' + key, handler);
                app[method](key, handler);
            });
        });

        return routes;
    };

    return {get: getRoutes, install: installRoutes};
}());<|endoftext|>


<commit_before>var express = require('express');
var fs = require('fs');
var app = express();
var storagePath = "/data/toilet_status.txt";

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/update', function(req, res) {
  console.log(new Date().toString(), "Received update:", req.params.status);
  fs.writeFileSync(storagePath, JSON.stringify({ status: req.params.status }));
  res.json({ success: true });
});

app.get('/status', function(req, res) {
  var data = fs.readFileSync(storagePath);
  res.json(JSON.parse(data));
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});
<commit_msg>New storage path<commit_after>var express = require('express');
var fs = require('fs');
var app = express();
var storagePath = "./toilet_status.txt";

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/update', function(req, res) {
  console.log(new Date().toString(), "Received update:", req.params.status);
  fs.writeFileSync(storagePath, JSON.stringify({ status: req.params.status }));
  res.json({ success: true });
});

app.get('/status', function(req, res) {
  try {
    var data = fs.readFileSync(storagePath);
    res.json(JSON.parse(data));
  } catch(e) {
    res.json({ status: "no data yet" });
  }
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');
var EOL = require('os').EOL;

var through = require('through2');
var gutil = require('gulp-util');
var glob = require('glob');

module.exports = function(options) {
  options = options || {};
  var startReg = /<!--\s*build:(\w+)(?:\(([^\)]+?)\))?\s+(\/?([^\s]+?))?\s*-->/gim;
  var endReg = /<!--\s*endbuild\s*-->/gim;
  var jsReg = /<\s*script\s+.*?src\s*=\s*("|')([^"']+?)\1.*?><\s*\/\s*script\s*>/gi;
  var cssReg = /<\s*link\s+.*?href\s*=\s*("|')([^"']+)\1.*?>/gi;
  var startCondReg = /<!--\[[^\]]+\]>/gim;
  var endCondReg = /<!\[endif\]-->/gim;
  var basePath, mainPath, mainName, alternatePath;

  function createFile(name, content) {
    var filePath = path.join(path.relative(basePath, mainPath), name)
      var isStatic = name.split('.').pop() === 'js' || name.split('.').pop() === 'css'

      if (options.outputRelativePath && isStatic)
        filePath = options.outputRelativePath + name;

    return new gutil.File({
      path: filePath,
      contents: new Buffer(content)
    })
  }

  function getBlockType(content) {
    return jsReg.test(content) ? 'js' : 'css';
  }

  function getFiles(content, reg) {
    var paths = [];
    var files = [];

    content
      .replace(startCondReg, '')
      .replace(endCondReg, '')
      .replace(/<!--(?:(?:.|\r|\n)*?)-->/gim, '')
      .replace(reg, function (a, quote, b) {
        var filePath = path.resolve(path.join(alternatePath || mainPath, b));

        if (options.assetsDir)
          filePath = path.resolve(path.join(options.assetsDir, path.relative(basePath, filePath)));

        paths.push(filePath);
      });

    for (var i = 0, l = paths.length; i < l; ++i) {
      var filepaths = glob.sync(paths[i]);
      if(filepaths[0] === undefined) {
        throw new gutil.PluginError('gulp-usemin', 'Path ' + paths[i] + ' not found!');
      }
      filepaths.forEach(function (filepath) {
        files.push(new gutil.File({
          path: filepath,
          contents: fs.readFileSync(filepath)
        }));
      });
    }

    return files;
  }

  function concat(files, name) {
    var buffer = [];

    files.forEach(function(file) {
      buffer.push(String(file.contents));
    });

    return createFile(name, buffer.join(EOL));
  }

  function processTask(index, tasks, name, files, callback) {
    var newFiles = [];

    if (tasks[index] == 'concat') {
      newFiles = [concat(files, name)];
    }
    else {
      var stream = tasks[index];

      function write(file) {
        newFiles.push(file);
      }

      stream.on('data', write);
      files.forEach(function(file) {
        stream.write(file);
      });
      stream.removeListener('data', write);
    }

    if (tasks[++index])
      processTask(index, tasks, name, newFiles, callback);
    else
      newFiles.forEach(callback);
  }

  function process(name, files, pipelineId, callback) {
    var tasks = options[pipelineId] || [];
    if (tasks.indexOf('concat') == -1)
      tasks.unshift('concat');

    processTask(0, tasks, name, files, callback);
  }

  function processHtml(content, push, callback) {
    var html = [];
    var sections = content.split(endReg);

    for (var i = 0, l = sections.length; i < l; ++i) {
      if (sections[i].match(startReg)) {
        var section = sections[i].split(startReg);
        alternatePath = section[2];

        html.push(section[0]);

        var startCondLine = section[5].match(startCondReg);
        var endCondLine = section[5].match(endCondReg);
        if (startCondLine && endCondLine)
          html.push(startCondLine[0]);

        if (section[1] !== 'remove') {
          if (getBlockType(section[5]) == 'js') {
            process(section[4], getFiles(section[5], jsReg), section[1], function(name, file) {
              push(file);
              if (path.extname(file.path) == '.js')
                html.push('<script src="' + name.replace(path.basename(name), path.basename(file.path)) + '"></script>');
            }.bind(this, section[3]));
          } else {
            process(section[4], getFiles(section[5], cssReg), section[1], function(name, file) {
              push(file);
              html.push('<link rel="stylesheet" href="' + name.replace(path.basename(name), path.basename(file.path)) + '"/>');
            }.bind(this, section[3]));
          }
        }

        if (startCondLine && endCondLine) {
          html.push(endCondLine[0]);
        }
      } else {
        html.push(sections[i]);
      }
    }
    process(mainName, [createFile(mainName, html.join(''))], 'html', function(file) {
      push(file);
      callback();
    });
  }

  return through.obj(function(file, enc, callback) {
    if (file.isNull()) {
      this.push(file); // Do nothing if no contents
      callback();
    }
    else if (file.isStream()) {
      this.emit('error', new gutil.PluginError('gulp-usemin', 'Streams are not supported!'));
      callback();
    }
    else {
      basePath = file.base;
      mainPath = path.dirname(file.path);
      mainName = path.basename(file.path);

      processHtml(String(file.contents), this.push.bind(this), callback);
    }
  });
};
<commit_msg>changed regex expression to accept single quotes as well as double quotes<commit_after>var path = require('path');
var fs = require('fs');
var EOL = require('os').EOL;

var through = require('through2');
var gutil = require('gulp-util');
var glob = require('glob');

module.exports = function(options) {
  options = options || {};
  var startReg = /<!--\s*build:(\w+)(?:\(([^\)]+?)\))?\s+(\/?([^\s]+?))?\s*-->/gim;
  var endReg = /<!--\s*endbuild\s*-->/gim;
  var jsReg = /<\s*script\s+.*?src\s*=\s*(?:'|")([^'"]+?)(?:'|").*?><\s*\/\s*script\s*>/gi;
  var cssReg = /<\s*link\s+.*?href\s*=\s*(?:'|")([^'"]+)(?:'|").*?>/gi;
  var startCondReg = /<!--\[[^\]]+\]>/gim;
  var endCondReg = /<!\[endif\]-->/gim;
  var basePath, mainPath, mainName, alternatePath;

  function createFile(name, content) {
    var filePath = path.join(path.relative(basePath, mainPath), name)
      var isStatic = name.split('.').pop() === 'js' || name.split('.').pop() === 'css'

      if (options.outputRelativePath && isStatic)
        filePath = options.outputRelativePath + name;

    return new gutil.File({
      path: filePath,
      contents: new Buffer(content)
    })
  }

  function getBlockType(content) {
    return jsReg.test(content) ? 'js' : 'css';
  }

  function getFiles(content, reg) {
    var paths = [];
    var files = [];

    content
      .replace(startCondReg, '')
      .replace(endCondReg, '')
      .replace(/<!--(?:(?:.|\r|\n)*?)-->/gim, '')
      .replace(reg, function (a, quote, b) {
        var filePath = path.resolve(path.join(alternatePath || mainPath, b));

        if (options.assetsDir)
          filePath = path.resolve(path.join(options.assetsDir, path.relative(basePath, filePath)));

        paths.push(filePath);
      });

    for (var i = 0, l = paths.length; i < l; ++i) {
      var filepaths = glob.sync(paths[i]);
      if(filepaths[0] === undefined) {
        throw new gutil.PluginError('gulp-usemin', 'Path ' + paths[i] + ' not found!');
      }
      filepaths.forEach(function (filepath) {
        files.push(new gutil.File({
          path: filepath,
          contents: fs.readFileSync(filepath)
        }));
      });
    }

    return files;
  }

  function concat(files, name) {
    var buffer = [];

    files.forEach(function(file) {
      buffer.push(String(file.contents));
    });

    return createFile(name, buffer.join(EOL));
  }

  function processTask(index, tasks, name, files, callback) {
    var newFiles = [];

    if (tasks[index] == 'concat') {
      newFiles = [concat(files, name)];
    }
    else {
      var stream = tasks[index];

      function write(file) {
        newFiles.push(file);
      }

      stream.on('data', write);
      files.forEach(function(file) {
        stream.write(file);
      });
      stream.removeListener('data', write);
    }

    if (tasks[++index])
      processTask(index, tasks, name, newFiles, callback);
    else
      newFiles.forEach(callback);
  }

  function process(name, files, pipelineId, callback) {
    var tasks = options[pipelineId] || [];
    if (tasks.indexOf('concat') == -1)
      tasks.unshift('concat');

    processTask(0, tasks, name, files, callback);
  }

  function processHtml(content, push, callback) {
    var html = [];
    var sections = content.split(endReg);

    for (var i = 0, l = sections.length; i < l; ++i) {
      if (sections[i].match(startReg)) {
        var section = sections[i].split(startReg);
        alternatePath = section[2];

        html.push(section[0]);

        var startCondLine = section[5].match(startCondReg);
        var endCondLine = section[5].match(endCondReg);
        if (startCondLine && endCondLine)
          html.push(startCondLine[0]);

        if (section[1] !== 'remove') {
          if (getBlockType(section[5]) == 'js') {
            process(section[4], getFiles(section[5], jsReg), section[1], function(name, file) {
              push(file);
              if (path.extname(file.path) == '.js')
                html.push('<script src="' + name.replace(path.basename(name), path.basename(file.path)) + '"></script>');
            }.bind(this, section[3]));
          } else {
            process(section[4], getFiles(section[5], cssReg), section[1], function(name, file) {
              push(file);
              html.push('<link rel="stylesheet" href="' + name.replace(path.basename(name), path.basename(file.path)) + '"/>');
            }.bind(this, section[3]));
          }
        }

        if (startCondLine && endCondLine) {
          html.push(endCondLine[0]);
        }
      } else {
        html.push(sections[i]);
      }
    }
    process(mainName, [createFile(mainName, html.join(''))], 'html', function(file) {
      push(file);
      callback();
    });
  }

  return through.obj(function(file, enc, callback) {
    if (file.isNull()) {
      this.push(file); // Do nothing if no contents
      callback();
    }
    else if (file.isStream()) {
      this.emit('error', new gutil.PluginError('gulp-usemin', 'Streams are not supported!'));
      callback();
    }
    else {
      basePath = file.base;
      mainPath = path.dirname(file.path);
      mainName = path.basename(file.path);

      processHtml(String(file.contents), this.push.bind(this), callback);
    }
  });
};
<|endoftext|>


<commit_before>var _      = require('lodash-node'),
    zlib   = require('zlib'),
    spawn  = require('child_process').spawn;

exports.record = function (options, callback) {

  var recording = '';

  var defaults = {
    sampleRate: 16000,
    compress: false
  };

  options = _.merge(options, defaults);

  // capture audio stream
  var cmd = 'sox';
  var cmdArgs = [
    '-q',
    '-b','16',
    '-d','-t','wav','-',
    'rate','16000','channels','1',
    'silence','1','0.1',(options.threshold || '0.1')+'%','1','1.0',(options.threshold || '0.1')+'%'
  ];

  console.log('Recording...');

  var rec = spawn(cmd, cmdArgs, 'pipe');

  // process stdout
  rec.stdout.setEncoding('binary');
  rec.stdout.on('data', function (data) {
    console.log('Receiving data...');
    recording += data;
  });

  // exit recording
  rec.on('close', function (code) {
    callback(null, recording);
  });

};

exports.compress = function (input, callback) {

  console.log('Compressing...');
  console.time('Compressed');

  zlib.gzip(input, function (err, result) {

    console.timeEnd('Compressed');
    console.log('Compressed size:', result.length, 'bytes');

    if (err) callback(err);

    callback(null, result);

  });

};<commit_msg>return binary buffer<commit_after>var _      = require('lodash-node'),
    zlib   = require('zlib'),
    spawn  = require('child_process').spawn;

exports.record = function (options, callback) {

  var recording = '';

  var defaults = {
    sampleRate: 16000,
    compress: false
  };

  options = _.merge(options, defaults);

  // capture audio stream
  var cmd = 'sox';
  var cmdArgs = [
    '-q',
    '-b','16',
    '-d','-t','wav','-',
    'rate','16000','channels','1',
    'silence','1','0.1',(options.threshold || '0.1')+'%','1','1.0',(options.threshold || '0.1')+'%'
  ];

  console.log('Recording...');

  var rec = spawn(cmd, cmdArgs, 'pipe');

  // process stdout
  rec.stdout.setEncoding('binary');
  rec.stdout.on('data', function (data) {
    console.log('Receiving data...');
    recording += data;
  });

  // exit recording
  rec.on('close', function (code) {
    var buff = new Buffer(recording, 'binary');
    callback(null, buff);
  });

};

exports.compress = function (input, callback) {

  console.log('Compressing...');
  console.time('Compressed');

  zlib.gzip(input, function (err, result) {

    console.timeEnd('Compressed');
    console.log('Compressed size:', result.length, 'bytes');

    if (err) callback(err);

    callback(null, result);

  });

};<|endoftext|>


<commit_before>var through = require('through2');
var recast = require('recast');

var transformer = require('./unreachableBranchTransformer');

module.exports = function (file, opts) {
  opts = opts || [];
  var ignore = ['.json'].concat(opts.ignore || []).some(function(ext) {
    return file.indexOf(ext, file.length - ext.length) !== -1;
  });

  if (ignore) {
    return through();
  }

  var buffers = [];
  return through(function(chunk, enc, cb) {
    buffers.push(chunk);
    cb();
  }, function(cb) {
    var source = Buffer.concat(buffers).toString();
    this.push(transform(source));
    cb();
  });
};

function transform(code/*, opts*/) {
  return recast.print( transformer( recast.parse(code) ) ).code;
}

module.exports.transform = transform;
<commit_msg>Make `file` argument optional, Resolves #4<commit_after>var through = require('through2');
var recast = require('recast');

var transformer = require('./unreachableBranchTransformer');

module.exports = function (file, opts) {
  if (typeof file === 'string') {
    opts = opts || [];
    var ignore = ['.json'].concat(opts.ignore || []).some(function(ext) {
      return file.indexOf(ext, file.length - ext.length) !== -1;
    });

    if (ignore) {
      return through();
    }
  }

  var buffers = [];
  return through(function(chunk, enc, cb) {
    buffers.push(chunk);
    cb();
  }, function(cb) {
    var source = Buffer.concat(buffers).toString();
    this.push(transform(source));
    cb();
  });
};

function transform(code/*, opts*/) {
  return recast.print( transformer( recast.parse(code) ) ).code;
}

module.exports.transform = transform;
<|endoftext|>


<commit_before>/*
 Squidwarc  Copyright (C) 2017  John Berlin <n0tan3rd@gmail.com>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Squidwarc is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this Squidwarc.  If not, see <http://www.gnu.org/licenses/>
 */

const program = require('commander')
const R = require('ramda')
const configRunner = require('./lib/runners').configRunner
const cp = require('./lib/utils/colorPrinters')

process.on('unhandledRejection', function (reason, p) {
  console.log('Unhandled Rejection:', reason.stack)
  // or next(reason);
})

program
  .version('1.0.0', '-v, --version')
  .option('-c, --config <path-to-config.json>', 'Launch A Crawl From A Config')

program.parse(process.argv)
if (program.rawArgs.slice(2).length === 0) {
  cp.green(program.helpInformation())
  // process.exit(1)
} else {
  if (!R.isNil(program.config)) {
    cp.crawlerOpt('Running Crawl From Config File', program.config)
    configRunner(program.config)
  } else {
    cp.bred('Config argument (-c) was no supplied.')
  }
}
<commit_msg>Fix grammatical error...again.<commit_after>/*
 Squidwarc  Copyright (C) 2017  John Berlin <n0tan3rd@gmail.com>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Squidwarc is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this Squidwarc.  If not, see <http://www.gnu.org/licenses/>
 */

const program = require('commander')
const R = require('ramda')
const configRunner = require('./lib/runners').configRunner
const cp = require('./lib/utils/colorPrinters')

process.on('unhandledRejection', function (reason, p) {
  console.log('Unhandled Rejection:', reason.stack)
  // or next(reason);
})

program
  .version('1.0.0', '-v, --version')
  .option('-c, --config <path-to-config.json>', 'Launch A Crawl From A Config')

program.parse(process.argv)
if (program.rawArgs.slice(2).length === 0) {
  cp.green(program.helpInformation())
  // process.exit(1)
} else {
  if (!R.isNil(program.config)) {
    cp.crawlerOpt('Running Crawl From Config File', program.config)
    configRunner(program.config)
  } else {
    cp.bred('Config argument (-c) was not supplied.')
  }
}
<|endoftext|>


<commit_before>'use strict';

var request = require("request")
	, assign = require('object-assign')
	, MemoryStream = require('memory-stream')
	, zlib = require("zlib")
	;

var jobs = {
	parallel: require('./parallel'),
	queue:    require('./queue')
};

/**
 * @class
 * @param {object} [opts] - Options for <request>
 */
function Downloader(opts) {
	this.opts = opts || {};
	this.opts.encoding = null;
	this.opts.timeout = ('timeout' in this.opts) ? this.opts.timeout : 60*1000;
	this.tasks = [];

	this.mode = ('mode' in this.opts) ? this.opts.mode : "parallel";
}

// generator of tasks
var generator = function(url, opts) {
	// task func
	return function(cb) {
		var wstream = opts.stream || new MemoryStream()
			, name = null
			, maxSize = 0
			;

		if (typeof opts.maxSize === 'number' && opts.maxSize > 0) {
			maxSize = opts.maxSize;
			delete opts.maxSize;
		}

		if (opts.stream) {
			delete opts.stream;
		}

		var onFinishStream = function() {
			var content;

			if (wstream instanceof MemoryStream) {
				content = wstream.toBuffer();
			} else {
				content = new Buffer(0);
			}

			return cb(null, {url:url, filename:name, content:content});
		};

		wstream.on('finish', onFinishStream);

		var httpreq = request.get(url, opts)
		.on("error", function(err){
			cb({url:url, error:err});
		})
		.on('response', function (res) {
			if (res.statusCode < 200 || res.statusCode >= 300) {
				return cb({url:url, error: new Error(res.statusCode)});
			}

			if (res.headers.hasOwnProperty("content-disposition")) {
				var attach = res.headers["content-disposition"];
				var posLeft = attach.indexOf('"');

				name = attach.slice(posLeft+1, -1);
			}

			var dataStream;

			var contentEncoding = res.headers['content-encoding'] || 'identity'
			contentEncoding = contentEncoding.trim().toLowerCase();

			if (contentEncoding === 'gzip') {
				dataStream = zlib.createGunzip();
				res.pipe(dataStream);
			} else {
				dataStream = res;
			}

			if (maxSize > 0) {
				var size = 0;
				var dataListener = function(chunk) {
					var part = Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk);
					size += part.length;

					if (size > maxSize) {
						httpreq.abort();

						dataStream.unpipe(wstream);
						dataStream.removeListener('data', dataListener);

						wstream.removeAllListeners('finish');
						wstream = null;

						return cb({url:url, error:new Error('Exceeds the maximum allowable size of the buffer')});
					}
				};

				dataStream.on('data', dataListener);
			}

			dataStream.pipe(wstream);
		})
		;
	};
};

/* @typedef {string} Url */

/**
 * @param {Url|Url[]} url
 * @param {object} [opts] - Options for <request>
 */
Downloader.prototype.get = function(url, opts) {
	if (typeof url === "string") {
		this.tasks.push( generator(url, assign({}, this.opts, opts)) );
	} else if (Array.isArray(url)) {
		url.forEach(function(item){
			this.tasks.push( generator(item, assign({}, this.opts, opts)) );
		}, this);
	} else {
		throw new TypeError("Argiment 1: expected string or array");
	}

	return this;
};

/**
 * @typedef ResultHash
 * @type {object}
 * @property {Url} url
 * @property {Buffer} content - Downloaded data
 * @property {null|String} filename - File name from `content-disposition` header
 */

 /**
  * @typedef ErrorHash
  * @type {object}
  * @property {Url} url
  * @property {Error} error
  */

/**
 * @callback RunCallback
 * @param {null|ErrorHash[]} err - Array of errors
 * @param {ResultHash[]} result
 */

/**
 * @param {RunCallback} cb
 */
Downloader.prototype.run = function(cb) {
	var opts = {};

	if (this.mode == "queue" && typeof this.opts.tryTimeout === 'number' && this.opts.tryTimeout > 0) {
		opts.timeout = this.opts.tryTimeout;
	}

	jobs[this.mode](this.tasks, opts, cb);
};

/**
 * Simple parallel downloader
 * @param {Url|Url[]} urls
 * @param {object}  [opts]
 * @param {RunCallback} cb
 */
function download(urls, opts, cb) {
	/*jshint validthis:true */
	if (this instanceof download) {
		opts = opts || urls;
		return new Downloader(opts);
	}

	if (!Array.isArray(urls) && (typeof urls !== "string")) {
		throw new TypeError("Expected string or array");
	}

	if (typeof opts === "function") {
		cb = opts;
		opts = {};
	}

	var d = new Downloader(opts);
	d.get(urls);
	d.run(cb);
}

module.exports = download;<commit_msg>[+] support other http methods<commit_after>'use strict';

var request = require("request")
	, assign = require('object-assign')
	, MemoryStream = require('memory-stream')
	, zlib = require("zlib")
	;

var jobs = {
	parallel: require('./parallel'),
	queue:    require('./queue')
};

/**
 * @class
 * @param {object} [opts] - Options for <request>
 */
function Downloader(opts) {
	this.opts = opts || {};
	this.opts.encoding = null;
	this.opts.timeout = ('timeout' in this.opts) ? this.opts.timeout : 60*1000;
	this.tasks = [];

	this.mode = ('mode' in this.opts) ? this.opts.mode : "parallel";
}

// generator of tasks
var generator = function(url, opts) {
	// task func
	return function(cb) {
		var wstream = opts.stream || new MemoryStream()
			, name = null
			, maxSize = 0
			;

		if (typeof opts.maxSize === 'number' && opts.maxSize > 0) {
			maxSize = opts.maxSize;
			delete opts.maxSize;
		}

		if (opts.stream) {
			delete opts.stream;
		}

		var onFinishStream = function() {
			var content;

			if (wstream instanceof MemoryStream) {
				content = wstream.toBuffer();
			} else {
				content = new Buffer(0);
			}

			return cb(null, {url:url, filename:name, content:content});
		};

		wstream.on('finish', onFinishStream);

		var httpreq = request(url, opts)
		.on("error", function(err){
			cb({url:url, error:err});
		})
		.on('response', function (res) {
			if (res.statusCode < 200 || res.statusCode >= 300) {
				return cb({url:url, error: new Error(res.statusCode)});
			}

			if (res.headers.hasOwnProperty("content-disposition")) {
				var attach = res.headers["content-disposition"];
				var posLeft = attach.indexOf('"');

				name = attach.slice(posLeft+1, -1);
			}

			var dataStream;

			var contentEncoding = res.headers['content-encoding'] || 'identity'
			contentEncoding = contentEncoding.trim().toLowerCase();

			if (contentEncoding === 'gzip') {
				dataStream = zlib.createGunzip();
				res.pipe(dataStream);
			} else {
				dataStream = res;
			}

			if (maxSize > 0) {
				var size = 0;
				var dataListener = function(chunk) {
					var part = Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk);
					size += part.length;

					if (size > maxSize) {
						httpreq.abort();

						dataStream.unpipe(wstream);
						dataStream.removeListener('data', dataListener);

						wstream.removeAllListeners('finish');
						wstream = null;

						return cb({url:url, error:new Error('Exceeds the maximum allowable size of the buffer')});
					}
				};

				dataStream.on('data', dataListener);
			}

			dataStream.pipe(wstream);
		})
		;
	};
};

/* @typedef {string} Url */

/**
 * @param {Url|Url[]} url
 * @param {object} [opts] - Options for <request>
 */
Downloader.prototype.get = function(url, opts) {
	if (typeof url === "string") {
		this.tasks.push( generator(url, assign({}, this.opts, opts)) );
	} else if (Array.isArray(url)) {
		url.forEach(function(item){
			this.tasks.push( generator(item, assign({}, this.opts, opts)) );
		}, this);
	} else {
		throw new TypeError("Argiment 1: expected string or array");
	}

	return this;
};

/**
 * @typedef ResultHash
 * @type {object}
 * @property {Url} url
 * @property {Buffer} content - Downloaded data
 * @property {null|String} filename - File name from `content-disposition` header
 */

 /**
  * @typedef ErrorHash
  * @type {object}
  * @property {Url} url
  * @property {Error} error
  */

/**
 * @callback RunCallback
 * @param {null|ErrorHash[]} err - Array of errors
 * @param {ResultHash[]} result
 */

/**
 * @param {RunCallback} cb
 */
Downloader.prototype.run = function(cb) {
	var opts = {};

	if (this.mode == "queue" && typeof this.opts.tryTimeout === 'number' && this.opts.tryTimeout > 0) {
		opts.timeout = this.opts.tryTimeout;
	}

	jobs[this.mode](this.tasks, opts, cb);
};

/**
 * Simple parallel downloader
 * @param {Url|Url[]} urls
 * @param {object}  [opts]
 * @param {RunCallback} cb
 */
function download(urls, opts, cb) {
	/*jshint validthis:true */
	if (this instanceof download) {
		opts = opts || urls;
		return new Downloader(opts);
	}

	if (!Array.isArray(urls) && (typeof urls !== "string")) {
		throw new TypeError("Expected string or array");
	}

	if (typeof opts === "function") {
		cb = opts;
		opts = {};
	}

	var d = new Downloader(opts);
	d.get(urls);
	d.run(cb);
}

module.exports = download;<|endoftext|>


<commit_before>var transformTools = require('browserify-transform-tools');
var resolve = require('resolve');
var path = require('path');

var transform = transformTools.makeRequireTransform(
    "resolvify",
    {
        evaluateArguments: true,
        jsFilesOnly: true
    },
    function(args, opts, cb) {
        resolved = resolve.sync(args[0], {
            basedir: path.dirname(opts.file),
            moduleDirectory: ['node_modules'].concat(opts.config)
        });

        return cb(null, "require('"+resolved+"')");
    }
);

module.exports = transform;<commit_msg>Picking both options and cli params into paths variable<commit_after>var transformTools = require('browserify-transform-tools');
var resolve = require('resolve');
var path = require('path');

var transform = transformTools.makeRequireTransform(
    "resolvify",
    {
        evaluateArguments: true,
        jsFilesOnly: true
    },
    function(args, opts, cb) {
        var paths = Object.keys(opts.config)
                        .filter(function(opts_key) { return opts_key.length == 1 })
                        .reduce(function(coll, opts_key) {
                            return coll.concat(opts.config[opts_key])
                        },[])
        if (paths.length == 0) { return cb(null) }
        resolved = resolve.sync(args[0], {
            basedir: path.dirname(opts.file),
//            basedir: __dirname,
            moduleDirectory: ['node_modules'].concat(paths)
        });

        return cb(null, "require('"+resolved+"')");
    }
);

module.exports = transform;
<|endoftext|>


<commit_before>'use strict';
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
///// Cluster Code /////
///
const PORT = 8000;

if (cluster.isMaster) {
  console.log(`Master here (pid: ${process.pid}):`);
  console.log(`Based on your current hardware, ${numCPUs} workers will be started...`);
  console.log(`Listening on 0.0.0.0:${PORT}`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster
    .on('SIGTERM', () => cluster.off('exit'))
    .on('exit', (deadWorker) => {
      console.warn(`${deadWorker.process.pid} died, forking new process...`);
      cluster.fork();
    });
  return;
}

///// Worker Code /////

const pjson   = require('./package.json');

const path     = require('path');
const fs       = require('fs');
const http     = require('http');
const zlib     = require('zlib');

const mime     = require('mime');
const Throttle = require('stream-throttle').Throttle;

const rateLimit = 0; //3 * 1024 * 1024; // bps == 3 MB/s
const baseUrl   = './www';

function handleRequest(request, response) {
  const url = path.join(baseUrl, path.normalize(decodeURIComponent(request.url)));

  console.log(`#${cluster.worker.id}: HTTP/${request.httpVersion} ${request.method} ${request.url}`);

  response.setHeader('Server', `${pjson.name}/${pjson.version}`);

  fs.stat(url, (error, stat) => {
    if (error || stat.isDirectory()) {
      response.writeHead(404);
      return response.end('Not found');
    }

    const acceptEncoding = (request.headers['accept-encoding'] || '').split(',').map(s => s.trim());
    const contentType    = mime.lookup(url);
    const isBinary       = ['application/javascript', 'text/'].every(s => !contentType.startsWith(s));

    response.setHeader('Content-Type', contentType);

    let compressionStream;

    if (!isBinary) {
      ['deflate', 'gzip'].some((encoding) => {
        if (acceptEncoding.includes(encoding)) {
          response.setHeader('Content-Encoding', encoding);
          const method = 'create' + encoding.replace(/^./, c => c.toUpperCase());
          compressionStream = zlib[method]({
            flush: zlib.Z_PARTIAL_FLUSH,
            level: zlib.Z_BEST_COMPRESSION,
          });
          return true;
        }
      });
    }

    let data;
    let partial;

    if (request.headers.range) {
      const {range} = request.headers;
      const [partialStart, partialEnd] = range.replace(/bytes=/, '').split('-');
      const start = parseInt(partialStart, 10);
      const end = partialEnd ? parseInt(partialEnd, 10) : stat.size - 1;

      partial = {
        start,
        end,
        chunkSize: (end - start) + 1,
      };

      data = fs.createReadStream(url, partial);
    } else {
      data = fs.createReadStream(url);
    }

    if (compressionStream) {
      data = data.pipe(compressionStream);
    } else {
      response.setHeader('Content-Length', partial ? partial.chunkSize : stat.size);
    }

    if (rateLimit > 0) {
      data = data.pipe(new Throttle({rate: rateLimit}));
    }

    if (!partial) {
      response.writeHead(200);
    } else {
      response.writeHead(206, {
        'Content-Range': `bytes ${partial.start}-${partial.end}/${stat.size}`,
        'Accept-Ranges': 'bytes',
      });
    }
    data.pipe(response);
  });
}

http
  .createServer(handleRequest)
  .listen(PORT, () => console.log(`${cluster.worker.id} is ready (pid: ${process.pid})`));
<commit_msg>Code cleanup<commit_after>'use strict';
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
///// Cluster Code /////

const PORT = 8000;

if (cluster.isMaster) {
  console.log(`Master here (pid: ${process.pid}):`);
  console.log(`Based on your current hardware, ${numCPUs} workers will be started...`);
  console.log(`Listening on 0.0.0.0:${PORT}`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster
    .on('SIGTERM', () => cluster.off('exit'))
    .on('exit', (deadWorker) => {
      console.warn(`${deadWorker.process.pid} died, forking new process...`);
      cluster.fork();
    });
  return;
}

///// Worker Code /////

const pjson   = require('./package.json');

const path     = require('path');
const fs       = require('fs');
const http     = require('http');
const zlib     = require('zlib');

const mime     = require('mime');
const Throttle = require('stream-throttle').Throttle;

const rateLimit = 0; //3 * 1024 * 1024; // bps == 3 MB/s
const baseUrl   = './www';

function handleRequest(request, response) {
  const url = path.join(baseUrl, path.normalize(decodeURIComponent(request.url)));

  console.log(`#${cluster.worker.id}: HTTP/${request.httpVersion} ${request.method} ${request.url}`);

  response.setHeader('Server', `${pjson.name}/${pjson.version}`);

  fs.stat(url, (error, stat) => {
    if (error || stat.isDirectory()) {
      response.writeHead(404);
      return response.end('Not found');
    }

    const acceptEncoding = (request.headers['accept-encoding'] || '').split(',').map(s => s.trim());
    const contentType    = mime.lookup(url);
    const isBinary       = ['application/javascript', 'text/'].every(s => !contentType.startsWith(s));

    response.setHeader('Content-Type', contentType);

    let compressionStream;

    if (!isBinary) {
      ['deflate', 'gzip'].some((encoding) => {
        if (acceptEncoding.includes(encoding)) {
          response.setHeader('Content-Encoding', encoding);
          const method = 'create' + encoding.replace(/^./, c => c.toUpperCase());
          compressionStream = zlib[method]({
            flush: zlib.Z_PARTIAL_FLUSH,
            level: zlib.Z_BEST_COMPRESSION,
          });
          return true;
        }
      });
    }

    let data;
    let partial;

    if (request.headers.range) {
      const {range} = request.headers;
      const [partialStart, partialEnd] = range.replace(/bytes=/, '').split('-');
      const start = parseInt(partialStart, 10);
      const end = partialEnd ? parseInt(partialEnd, 10) : stat.size - 1;

      partial = {
        start,
        end,
        chunkSize: (end - start) + 1,
      };

      data = fs.createReadStream(url, partial);
    } else {
      data = fs.createReadStream(url);
    }

    if (compressionStream) {
      data = data.pipe(compressionStream);
    } else {
      response.setHeader('Content-Length', partial ? partial.chunkSize : stat.size);
    }

    if (rateLimit > 0) {
      data = data.pipe(new Throttle({rate: rateLimit}));
    }

    if (!partial) {
      response.writeHead(200);
    } else {
      response.writeHead(206, {
        'Content-Range': `bytes ${partial.start}-${partial.end}/${stat.size}`,
        'Accept-Ranges': 'bytes',
      });
    }

    data.pipe(response);
  });
}

http
  .createServer(handleRequest)
  .listen(PORT, () => console.log(`${cluster.worker.id} is ready (pid: ${process.pid})`));
<|endoftext|>


<commit_before>"use strict";

var through = require("through2");
var uglifyjs = require("uglify-js");

var annoRe = /<!--[\s\S]*?-->|(?:\/\*[\s\S]*?\*\/)*/g;

// ignore script type
var ignoreScriptTypes = [
    "text/template",
    "x-tmpl-mustache"
];

/**
 * compressed html
 * @param nonote    remove annotation or not
 * @returns {*}
 */
var minify = function(nonote){
    var typeIgnoreRe = new RegExp(ignoreScriptTypes.join("|").replace(/\//g, "\\/"));

    var _transform = function(file, encoding, done){
        var str = file.contents.toString();
        var count = str.length + 1;
        var nline = "";
        var nstr = "";
        var index, ref, scripts;

        var scriptStart = false;

        // javascript collector
        var scol = [];

        //remove annotation like <!--XX--> or /**/
        if (!nonote) str = str.replace(annoRe, '');

        while (count-- > 0) {
            index = str.length - count;
            ref = str.charAt(index);

            //read file line by line
            if (ref.match(/\r|\n/) || index == str.length) {
                nline = nline.trim();

                if(!nline) continue;

                //template script filter
                if (nline.match(/^<script[^>]*?>$/g) && !nline.match(typeIgnoreRe)) {
                    nstr += nline;
                    scriptStart = true;
                } else if (scriptStart && nline.match(/^<\/script>$/g)) {
                    scripts = scol.join("\n");
                    scol.length = 0;
                    scriptStart = false;

                    //use uglifyjs to compressed the js in the html
                    try {
                        console.log(scripts)
                        nstr += uglifyjs.minify(scripts, {fromString: true}).code + nline;
                    } catch (e) {
                        console.log(e)
                        nstr += scripts + nline;
                    }

                } else if (scriptStart) {
                    scol.push(nline);
                } else {

                    if(/(?:<[a-z-]+)$/i.test(nstr)){
                        nstr += " ";
                    }

                    nstr += nline;
                }

                nline = "";
            } else {
                nline += ref;
            }
        }

        file.contents = new Buffer(nstr);

        this.push(file);

        done();
    };

    return through.obj(_transform);
};

module.exports = minify;<commit_msg>update<commit_after>"use strict";

var through = require("through2");
var uglifyjs = require("uglify-js");

var annoRe = /<!--[\s\S]*?-->|(?:\/\*[\s\S]*?\*\/)*/g;

// ignore script type
var ignoreScriptTypes = [
    "text/template",
    "x-tmpl-mustache"
];

/**
 * compressed html
 * @param nonote    remove annotation or not
 * @returns {*}
 */
var minify = function(nonote){
    var typeIgnoreRe = new RegExp(ignoreScriptTypes.join("|").replace(/\//g, "\\/"));

    var _transform = function(file, encoding, done){
        var str = file.contents.toString();
        var count = str.length + 1;
        var nline = "";
        var nstr = "";
        var index, ref, scripts;

        var scriptStart = false;

        // javascript collector
        var scol = [];

        //remove annotation like <!--XX--> or /**/
        if (!nonote) str = str.replace(annoRe, '');

        while (count-- > 0) {
            index = str.length - count;
            ref = str.charAt(index);

            //read file line by line
            if (ref.match(/\r|\n/) || index == str.length) {
                nline = nline.trim();

                if(!nline) continue;

                //template script filter
                if (nline.match(/^<script[^>]*?>$/g) && !nline.match(typeIgnoreRe)) {
                    nstr += nline;
                    scriptStart = true;
                } else if (scriptStart && nline.match(/^<\/script>$/g)) {
                    scripts = scol.join("\n");
                    scol.length = 0;
                    scriptStart = false;

                    //use uglifyjs to compressed the js in the html
                    try {
                        //console.log(scripts)
                        nstr += uglifyjs.minify(scripts, {fromString: true}).code + nline;
                    } catch (e) {
                        console.log(e)
                        nstr += scripts + nline;
                    }

                } else if (scriptStart) {
                    scol.push(nline);
                } else {

                    if(/(?:<[a-z-]+)$/i.test(nstr)){
                        nstr += " ";
                    }

                    nstr += nline;
                }

                nline = "";
            } else {
                nline += ref;
            }
        }

        file.contents = new Buffer(nstr);

        this.push(file);

        done();
    };

    return through.obj(_transform);
};

module.exports = minify;<|endoftext|>


<commit_before>(function(){

  function postJSON(uri, data, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST", uri, true);
    xmlHttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
    xmlHttp.onreadystatechange = function() {
      if(xmlHttp.readyState==4 && xmlHttp.status==200) {
        return callback(null, JSON.parse(xmlHttp.responseText));
      }
    };
    xmlHttp.send(typeof data === "string" ? data : JSON.stringify(data));
  };

  window.websqlSync = function(opts){
    Syncer.db = opts.db;
    return new Syncer(opts);
  }

  Syncer.orm = {

    /**
     * insert helper
     *  - orm.insert('tableName', {id: 1, val: 'foo'}, null, cb)
     * @param {String} table
     * @param {Object | Array} data
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     */
    insert: function(table, data, transaction, cb){

      if(!(data instanceof Array)){
        data = [data];
      }

      var cols = [];
      var values = [];

      for(var i=0; i<data.length; i++){
        var obj = data[i];
        values[i] = [];
        for(var p in obj){
          if(obj.hasOwnProperty(p)){
            if(i === 0) cols.push(p);
            values[i].push(obj[p]);
          }
        }
      }

      function insert(tx){
        var error = null
          , result = null
          , i = values.length;
          ;

        values.forEach(function(v){

          var sql = 'INSERT INTO '+table+' ('+cols.join(',')+') ' +
            'VALUES '+'("'+v.join('","')+'")';

          tx.executeSql(sql, null,
            function success(tx, res){
              i--;
              error = null;
              result = res;
              if(i === 0) cb(error, result, tx);
            },
            function error(tx, err){
              i--;
              error = err;
              if(i === 0) cb(error, result, tx);
            }
          );
//          console.log('returning', result);
//          return cb(error, result, tx);
        });
      }

      if(transaction){
        return insert(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return insert(tx);
        })
      }
    },

    /**
     * delete helper
     *  - orm.del('tableName', 'id = 1', null, cb)
     * @param {String} table
     * @param {String} constraints
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    del: function(table, constraints, transaction, cb){

      constraints = constraints ? ' WHERE '+constraints : '';

      function del(tx){
        tx.executeSql('DELETE FROM '+table+constraints+';',
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return del(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return del(tx);
        })
      }
    },

    /**
     * executes given query
     * @param {String} sql
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    query: function(sql, transaction, cb){

      function query(tx){
        tx.executeSql(sql,
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return query(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return query(tx);
        })
      }
    },

    /**
     * select helper
     * @param {String} table
     * @param {String} constraints
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    select: function(table, constraints, transaction, cb){

      constraints = constraints ? ' WHERE '+constraints : '';

      function select(tx){
        tx.executeSql('SELECT * FROM '+table+constraints+';',
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return select(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return select(tx);
        })
      }
    }
  }

  function Syncer(opts){
    this.opts = opts || {};
    this.url = opts.url || '';
    this.idCol = opts.id || 'id';
    this.tableName = this.opts.tableName;
    if(!this.tableName) throw Error('Syncer ~> missing table name in options');
  }

  Syncer.prototype.init = function(cb){
    Syncer.db.transaction(function(tx){
      tx.executeSql('CREATE TABLE IF NOT EXISTS _events' +
          ' (id TEXT, cmd TEXT)', null);
      tx.executeSql('CREATE TABLE IF NOT EXISTS _lastSync' +
        ' (ts TIMESTAMP)', null);
      tx.executeSql('SELECT * FROM _lastSync', null);
      return cb();
    });
  };

  Syncer.prototype.initTriggers = function(cb){
    var self = this
      ;
    Syncer.db.transaction(function(tx){
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS update_events_for_'+self.tableName+
        ' AFTER UPDATE ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (new.'+self.idCol+', "upsert"); END;', null);
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS insert_events_for_'+self.tableName+
        ' AFTER INSERT ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (new.'+self.idCol+', "upsert"); END;', null);
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS delete_events_for_'+self.tableName+
        ' AFTER DELETE ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (old.'+self.idCol+', "delete"); END;', null);
      return cb();
    });
  };

  Syncer.prototype.makePayload = function(cb){
    var payload = {
      upserts: [],
      deletes: []
    };

    Syncer.orm.query('SELECT * FROM '+this.tableName+' WHERE id IN' +
      ' (SELECT id FROM _events WHERE cmd LIKE "upsert")',
      null, function(err, res, tx){

        if(err) return cb(err, res);

        for(var i=0; i<res.rows.length; i++){
          payload.upserts.push(res.rows.item(i));
        }

        Syncer.orm.select('_events', 'cmd LIKE "delete"',tx,
          function(err, res, tx){

            if(err) return cb(err, res);

            for(var i=0; i<res.rows.length; i++){
              payload.deletes.push(res.rows.item(i));
            }

            Syncer.orm.query('SELECT * FROM _lastSync LIMIT 1', tx,
              function(err, res, tx){

              if(err) return cb(err, null, tx);

              // never synced
              if(res.rows.length === 0) payload.since = 0;
              else payload.since = res.rows.item(0).ts;

              cb(null, payload, tx);
            });
          });
      });
  };

  Syncer.prototype.sync = function(cb){
    var self = this;

    self.makePayload(function(err, payload, tx){

      // ids of affected items since last sync
      var ids = payload.upserts.map(function(i){
        return i.id;
      });

      postJSON(self.url, payload, function(err, serverResponse){
        if(err) return cb(err, null, tx);

        // we need new transaction, because this one wouldn't last through xhr
        Syncer.orm.del(self.tableName, 'id IN ("'+ids.join('","')+'")',
          null, function(err, res, tx){
            Syncer.orm.insert(self.tableName, serverResponse.upserts, tx, function(err, res, tx){
              Syncer.orm.del(self.tableName, self.idCol+' IN ("'+
                serverResponse.deletes.map(function(i){ return i.id; }).join('","')+'")', tx, function(err, res, tx){

                Syncer.orm.query('UPDATE _lastSync SET ts='
                  + serverResponse.serverTime, tx, function(err, res, tx){

                  // @fix we shouldn't delete events added during sinc, thus we need
                  // track them by id, or timestamp
                  Syncer.orm.del('_events', '', tx, function(err, res, tx){
                    return cb(null, res, tx);
                  });
                });
              });
            });
        });
      });
    });
  };

  window.websqlSync.orm = Syncer.orm;
  window.websqlSync.db = Syncer.db;
})();<commit_msg>edit expose postJSON, so it could be swapped by user impl<commit_after>;(function(){

  function postJSON(uri, data, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST", uri, true);
    xmlHttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
    xmlHttp.onreadystatechange = function() {
      if(xmlHttp.readyState==4 && xmlHttp.status==200) {
        return callback(null, JSON.parse(xmlHttp.responseText));
      }
    };
    xmlHttp.send(typeof data === "string" ? data : JSON.stringify(data));
  };

  window.websqlSync = function(opts){
    Syncer.db = opts.db;
    return new Syncer(opts);
  }

  Syncer.orm = {

    /**
     * insert helper
     *  - orm.insert('tableName', {id: 1, val: 'foo'}, null, cb)
     * @param {String} table
     * @param {Object | Array} data
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     */
    insert: function(table, data, transaction, cb){

      if(!(data instanceof Array)){
        data = [data];
      }

      var cols = [];
      var values = [];

      for(var i=0; i<data.length; i++){
        var obj = data[i];
        values[i] = [];
        for(var p in obj){
          if(obj.hasOwnProperty(p)){
            if(i === 0) cols.push(p);
            values[i].push(obj[p]);
          }
        }
      }

      function insert(tx){
        var error = null
          , result = null
          , i = values.length;
          ;

        values.forEach(function(v){

          var sql = 'INSERT INTO '+table+' ('+cols.join(',')+') ' +
            'VALUES '+'("'+v.join('","')+'")';

          tx.executeSql(sql, null,
            function success(tx, res){
              i--;
              error = null;
              result = res;
              if(i === 0) cb(error, result, tx);
            },
            function error(tx, err){
              i--;
              error = err;
              if(i === 0) cb(error, result, tx);
            }
          );
//          console.log('returning', result);
//          return cb(error, result, tx);
        });
      }

      if(transaction){
        return insert(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return insert(tx);
        })
      }
    },

    /**
     * delete helper
     *  - orm.del('tableName', 'id = 1', null, cb)
     * @param {String} table
     * @param {String} constraints
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    del: function(table, constraints, transaction, cb){

      constraints = constraints ? ' WHERE '+constraints : '';

      function del(tx){
        tx.executeSql('DELETE FROM '+table+constraints+';',
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return del(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return del(tx);
        })
      }
    },

    /**
     * executes given query
     * @param {String} sql
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    query: function(sql, transaction, cb){

      function query(tx){
        tx.executeSql(sql,
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return query(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return query(tx);
        })
      }
    },

    /**
     * select helper
     * @param {String} table
     * @param {String} constraints
     * @param {SQLTransaction} transaction
     * @param {Function} cb
     * @returns {*}
     */
    select: function(table, constraints, transaction, cb){

      constraints = constraints ? ' WHERE '+constraints : '';

      function select(tx){
        tx.executeSql('SELECT * FROM '+table+constraints+';',
          null,
          function success(tx, res){
            if(cb) cb(null, res, tx);
          },
          function error(tx, err){
            if(cb) cb(err, null, tx);
          }
        )
      }

      if(transaction){
        return select(transaction);
      } else {
        return Syncer.db.transaction(function(tx){
          return select(tx);
        })
      }
    }
  }

  function Syncer(opts){
    this.opts = opts || {};
    this.url = opts.url || '';
    this.idCol = opts.id || 'id';
    this.tableName = this.opts.tableName;
    if(!this.tableName) throw Error('Syncer ~> missing table name in options');
  }

  Syncer.prototype.init = function(cb){
    Syncer.db.transaction(function(tx){
      tx.executeSql('CREATE TABLE IF NOT EXISTS _events' +
          ' (id TEXT, cmd TEXT)', null);
      tx.executeSql('CREATE TABLE IF NOT EXISTS _lastSync' +
        ' (ts TIMESTAMP)', null);
      tx.executeSql('SELECT * FROM _lastSync', null);
      return cb();
    });
  };

  Syncer.prototype.initTriggers = function(cb){
    var self = this
      ;
    Syncer.db.transaction(function(tx){
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS update_events_for_'+self.tableName+
        ' AFTER UPDATE ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (new.'+self.idCol+', "upsert"); END;', null);
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS insert_events_for_'+self.tableName+
        ' AFTER INSERT ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (new.'+self.idCol+', "upsert"); END;', null);
      tx.executeSql('CREATE TRIGGER IF NOT EXISTS delete_events_for_'+self.tableName+
        ' AFTER DELETE ON '+self.tableName+' BEGIN ' +
        ' INSERT INTO _events (id, cmd) VALUES (old.'+self.idCol+', "delete"); END;', null);
      return cb();
    });
  };

  Syncer.prototype.makePayload = function(cb){
    var payload = {
      upserts: [],
      deletes: []
    };

    Syncer.orm.query('SELECT * FROM '+this.tableName+' WHERE id IN' +
      ' (SELECT id FROM _events WHERE cmd LIKE "upsert")',
      null, function(err, res, tx){

        if(err) return cb(err, res);

        for(var i=0; i<res.rows.length; i++){
          payload.upserts.push(res.rows.item(i));
        }

        Syncer.orm.select('_events', 'cmd LIKE "delete"',tx,
          function(err, res, tx){

            if(err) return cb(err, res);

            for(var i=0; i<res.rows.length; i++){
              payload.deletes.push(res.rows.item(i));
            }

            Syncer.orm.query('SELECT * FROM _lastSync LIMIT 1', tx,
              function(err, res, tx){

              if(err) return cb(err, null, tx);

              // never synced
              if(res.rows.length === 0) payload.since = 0;
              else payload.since = res.rows.item(0).ts;

              cb(null, payload, tx);
            });
          });
      });
  };

  Syncer.prototype.sync = function(cb){
    var self = this;

    self.makePayload(function(err, payload, tx){

      // ids of affected items since last sync
      var ids = payload.upserts.map(function(i){
        return i.id;
      });

      window.websqlSync.postJSON(self.url, payload, function(err, serverResponse){
        if(err) return cb(err, null, tx);

        // we need new transaction, because this one wouldn't last through xhr
        Syncer.orm.del(self.tableName, 'id IN ("'+ids.join('","')+'")',
          null, function(err, res, tx){
            Syncer.orm.insert(self.tableName, serverResponse.upserts, tx, function(err, res, tx){
              Syncer.orm.del(self.tableName, self.idCol+' IN ("'+
                serverResponse.deletes.map(function(i){ return i.id; }).join('","')+'")', tx, function(err, res, tx){

                Syncer.orm.query('UPDATE _lastSync SET ts='
                  + serverResponse.serverTime, tx, function(err, res, tx){

                  // @fix we shouldn't delete events added during sinc, thus we need
                  // track them by id, or timestamp
                  Syncer.orm.del('_events', '', tx, function(err, res, tx){
                    return cb(null, res, tx);
                  });
                });
              });
            });
        });
      });
    });
  };

  window.websqlSync.postJSON = postJSON;
  window.websqlSync.orm = Syncer.orm;
  window.websqlSync.db = Syncer.db;
})();<|endoftext|>


<commit_before>"use strict";

var request = require('request');

function main() {

}

main();<commit_msg>Created initial basic functionality.<commit_after>"use strict";

var fs = require('fs');
var request = require('request');

function siteCheck(site) {
	var options = {
		followRedirect: false,
		uri: site.requestUrl
	};
	if(site.requestHeaders) {
		options.headers = site.requestHeaders;
	}
	request.get(options, function(error, response, body){
		if(response.statusCode !== site.expectedStatus) {
			console.log('Failed check for ' + site.name +
					'. Expected HTTP status of ' + site.expectedStatus +
					' and got ' + response.statusCode + '.');
		} else {
			if(site.responseHeaders) {
				// TODO: Check response headers
				console.log('responseHeaders: ', site.responseHeaders);
			} else {
				console.log(site.name + ' working as expected.');
			}
		}
	});
}

function run(filename) {
	var file = require(filename);
	console.log(file);
	for(var i=0, n=file.sites.length; i<n; i++) {
		siteCheck(file.sites[i]);
	}
}

function main() {
	var standard = __dirname + '/checksites.json';
	var sample = __dirname + '/samplesites.json';
	if(fs.existsSync(standard)) {
		run(standard);
	} else if(fs.existsSync(sample)) {
		run(sample);
	} else {
		console.log('Expecting checksites.json or samplesites.json for data and expectation source');
	}
}

main();
<|endoftext|>


<commit_before>/*!
 * koa-better-body <https://github.com/tunnckoCore/koa-better-body>
 *
 * Copyright (c) 2014 Charlike Mike Reagent, Daryl Lau, contributors.
 * Released under the MIT license.
 */

'use strict';

/*!
 * Module dependencies.
 */

var buddy = require('co-body');
var forms = require('formidable');
var xtend = require('extend');

var defaultOptions = {
  patchNode: false,
  patchKoa: true,
  multipart: false,
  encoding: 'utf-8',
  jsonLimit: '1mb',
  formLimit: '56kb',
  formidable: {
    multiples: true,
    keepExtensions: true,
    maxFields: 10,
  }
};

/**
 * Doneable formidable
 *
 * @param  {Stream} ctx
 * @param  {Object} opts
 * @return {Function} Node-style callback, ready for yielding
 * @api private
 */
function formy(ctx, opts) {
  return function(done) {
    var form = new forms.IncomingForm(opts);
    form.parse(ctx.req, function(err, fields, files) {
      if (err) {return done(err);}
      done(null, {fields: fields, files: files});
    });
  };
}

/**
 * ## Examples
 * > For a more comprehensive examples, see [examples](./examples) folder.
 *
 * - [`examples/multer`](./examples/multer.js) - usage like Express's bodyParser - [multer][multer-url] `npm run examples-multer`
 * - [`examples/koa-router`](./examples/koa-router.js) - usage with Alex's [koa-router][koa-router-url] `npm run examples-koa-router`
 *
 *
 * ## Options
 * > However, `koa-better-body` have few custom options, see also [co-body][cobody-url], [raw-body][rawbody-url], [formidable][formidable-url]
 *
 * @param {Boolean} `patchNode` Patch request body to Node's `ctx.req` object, default `false`
 * @param {Boolean} `patchKoa` Patch request body to Koa's `ctx.request` object, default `true`
 * @param {String|Number} `jsonLimit` The byte limit of the JSON body, default `1mb`
 * @param {String|Number} `formLimit` The byte limit of the form body, default `56kb`
 * @param {String} `encoding` Sets encoding for incoming form fields, default `utf-8`
 * @param {Boolean} `multipart` Support `multipart/form-data` request bodies, default `false`
 * @param {Object} `formidable` Options that are passing to `formidable`
 * @param {Number} `formidable.maxFields` See [formidable-options](./readme.md#formidable-options). our default `10`
 * @param {Boolean} `formidable.multiples` See [formidable-options](./readme.md#formidable-options), our default `true`
 * @param {Boolean} `formidable.keepExtensions` See [formidable-options](./readme.md#formidable-options), our default `true`
 * @return {GeneratorFunction} That you can use with [koa][koa-url] or [co][co-url]
 * @api public
 */

module.exports = function koaBody(options) {
  var opts = xtend(true, defaultOptions, options || {});

  return function* koaBody(next){
    var body = {}, json, form;
    if (this.request.is('json'))  {
      json = yield buddy.json(this, {encoding: opts.encoding, limit: opts.jsonLimit});
      body.fields = json;
    }
    else if (this.request.is('urlencoded')) {
      form = yield buddy.form(this, {encoding: opts.encoding, limit: opts.formLimit});
      body.fields = form;
    }
    else if (this.request.is('multipart') && opts.multipart) {
      body = yield formy(this, opts.formidable);
    }

    if (opts.patchNode) {
      this.req.body = body;
    }
    if (opts.patchKoa) {
      this.request.body = body;
    }
    yield next;
  };
};
<commit_msg>fix issue with koa-passwport middleware<commit_after>/*!
 * koa-better-body <https://github.com/tunnckoCore/koa-better-body>
 *
 * Copyright (c) 2014 Charlike Mike Reagent, Daryl Lau, contributors.
 * Released under the MIT license.
 */

'use strict';

/*!
 * Module dependencies.
 */

var buddy = require('co-body');
var forms = require('formidable');
var xtend = require('extend');

var defaultOptions = {
  patchNode: false,
  patchKoa: true,
  multipart: false,
  encoding: 'utf-8',
  jsonLimit: '1mb',
  formLimit: '56kb',
  fieldsKey: 'fields',
  filesKey: 'files',
  formidable: {
    multiples: true,
    keepExtensions: true,
    maxFields: 10,
  }
};

/**
 * Doneable formidable
 *
 * @param  {Stream} ctx
 * @param  {Object} opts
 * @return {Function} Node-style callback, ready for yielding
 * @api private
 */
function formy(ctx, opts) {
  return function(done) {
    var form = new forms.IncomingForm(opts);
    form.parse(ctx.req, function(err, fields, files) {
      if (err) {return done(err);}
      done(null, {fields: fields, files: files});
    });
  };
}

function normalize(body, opts) {
  if (typeof opts.fieldsKey !== 'string') {
    body = body.fields;
  } else {
    body[opts.fieldsKey] = body.fields;
  }
  if (typeof opts.filesKey === 'string') {
    body[opts.filesKey] = body.files;
  }

  return body;
}

/**
 * ## Examples
 * > For a more comprehensive examples, see [examples](./examples) folder.
 *
 * - [`examples/multer`](./examples/multer.js) - usage like Express's bodyParser - [multer][multer-url] `npm run examples-multer`
 * - [`examples/koa-router`](./examples/koa-router.js) - usage with Alex's [koa-router][koa-router-url] `npm run examples-koa-router`
 *
 *
 * ## Options
 * > However, `koa-better-body` have few custom options, see also [co-body][cobody-url], [raw-body][rawbody-url], [formidable][formidable-url]
 *
 * @param {Boolean} `patchNode` Patch request body to Node's `ctx.req` object, default `false`
 * @param {Boolean} `patchKoa` Patch request body to Koa's `ctx.request` object, default `true`
 * @param {String|Number} `jsonLimit` The byte limit of the JSON body, default `1mb`
 * @param {String|Number} `formLimit` The byte limit of the form body, default `56kb`
 * @param {String} `encoding` Sets encoding for incoming form fields, default `utf-8`
 * @param {Boolean} `multipart` Support `multipart/form-data` request bodies, default `false`
 * @param {String|Boolean} `fieldsKey` Name of the key for fields in the body object, default `'fields'`
 * @param {String|Boolean} `filesKey` Name of the key for files in the body object, default `'files'`
 * @param {Object} `formidable` Options that are passing to `formidable`
 * @param {Number} `formidable.maxFields` See [formidable-options](./readme.md#formidable-options). our default `10`
 * @param {Boolean} `formidable.multiples` See [formidable-options](./readme.md#formidable-options), our default `true`
 * @param {Boolean} `formidable.keepExtensions` See [formidable-options](./readme.md#formidable-options), our default `true`
 * @return {GeneratorFunction} That you can use with [koa][koa-url] or [co][co-url]
 * @api public
 */

module.exports = function koaBody(options) {
  var opts = xtend(true, defaultOptions, options || {});

  return function* koaBody(next){
    var body = {}, json, form;
    if (this.request.is('json'))  {
      json = yield buddy.json(this, {encoding: opts.encoding, limit: opts.jsonLimit});
      body.fields = json;
    }
    else if (this.request.is('urlencoded')) {
      form = yield buddy.form(this, {encoding: opts.encoding, limit: opts.formLimit});
      body.fields = form;
    }
    else if (this.request.is('multipart') && opts.multipart) {
      body = yield formy(this, opts.formidable);
    }

    body = normalize(body, opts);

    if (opts.patchNode) {
      this.req.body = body;
    }
    if (opts.patchKoa) {
      this.request.body = body;
    }
    yield next;
  };
};
<|endoftext|>