<commit_before>'use strict';

var Mincer = require('mincer'),
    fs = require('fs')
;

var middleware = {};

/**
 * This is the connectMincer module which exposes a few methods to be used by the
 * individual middlewares.
 */
var connectMincer = (function() {

  var options = {},
      assetUrl,
      environment,
      manifest,
      production = false;

  /**
   * Initialize connectMincer with app options
   *
   * @param  {[type]} opts [description]
   * @return {[type]}      [description]
   */
  var configure = function(opts) {
    options = opts;

    production = opts.production === true ? true : false;

    if (!options.assetUrl) {
      assetUrl = '/assets';
    } else {
      assetUrl = options.assetUrl;
      if (assetUrl.substr(0, 1) !== '/') {
        assetUrl = '/' + assetUrl;
      }
      if (assetUrl.substr(-1) === '/') {
        assetUrl = assetUrl.substr(0, assetUrl.length - 1);
      }
    }

    environment = new Mincer.Environment(options.root);

    options.paths.forEach(function(path) {
      environment.appendPath(path);
    });

    // add some helpers
    environment.registerHelper('asset_path', function(name, opts) {
      var asset = environment.findAsset(name, opts);
      if (!asset) throw new Error("File [" + name + "] not found");
      if (production) {
        return toAssetUrl(asset.digestPath);
      } else {
        return toAssetUrl(asset.logicalPath);
      }
    });

    if (production) {
      // in production we use environment.index so any future calls
      // to environment will be cached
      environment = environment.index;

      // in production, we look up assets in the supplied manifest, so let's load that now
      if (fs.existsSync(options.manifestFile)) {
        manifest = require(options.manifestFile);
        if (!manifest.assets) manifest = null;
      }
    }
  };

  var toAssetUrl = function(source) {
    return options.assetUrl + '/' + source;
  };

  var findAssetPaths = function(logicalPath, ext) {

    if (production) {
      // we're in production, and have a valid manifest, so instead of using the environment
      // we will get the digestPath directly from the manifest
      //
      var digestPath;
      if (manifest)
        digestPath = manifest.assets[logicalPath];

      if (!digestPath) {
        // this is bad, and probably means someone forgot to do compile assets before running
        // in production.
        throw new Error("Asset [" + logicalPath + "] has not been compiled");
      }

      return [toAssetUrl(digestPath)];
    }

    // if we're in normal development mode, we should look for the asset in our current environment
    // and return it. It should already be compiled because we force a precompile in dev mode on
    // every request.

    var asset = environment.findAsset(logicalPath),
        paths = []
    ;

    if (!asset) return null;

    if (options.production) {
      // in production, return the asset with its digest path
      paths.push(toAssetUrl(asset.digestPath));
    } else if (asset.isCompiled) {
      asset.toArray().forEach(function(a) {
        paths.push(toAssetUrl(a.logicalPath) + '?body=1');
      });
    }

    return paths;
  };

  var helpers = {
    js: function(path) {
      var paths = findAssetPaths(path);

      if (!paths) throw new Error('Javascript asset [' + path + '] not found');

      var tags = paths.map(function(path) {
        return "<script src='" + path + "'></script>";
      });

      return tags.join("\n");
    },

    css: function(path) {
      var paths = findAssetPaths(path);

      if (!paths) throw new Error('CSS asset [' + path + '] not found');

      var tags = paths.map(function(path) {
        return "<link rel='stylesheet' href='" + path + "' />";
      });

      return tags.join("\n");
    },

    asset_path: function(path) {
      var paths = findAssetPaths(path);

      if (!paths) return '';

      // if this returns more than 1 thing just return the first
      return paths[0];
    }
  };

  return {
    configure: configure,
    helpers: helpers,
    getEnvironment: function() { return environment; },
    getManifest: function() { return manifest; },
    isProduction: function() { return production; }
  };

})();

/**
 * Set up the asset middleware.
 *
 * The asset middleware adds view helpers for loading js and css, and if in development mode
 * will also ensure assets are precompiled and route the mincer assetServer to /assetUrl
 *
 * The following helpers will be available in all views:
 *
 * - js()
 *   Accepts an asset name (e.g. 'app.js') and if found, outputs an appropriate <script> tag
 *
 * - css()
 *   Accepts an asset name (e.g. 'app.css') and if found, outputs an appropriate <link> tag
 *
 * - asset_path()
 *   Accepts an asset name (e.g. 'app.js') and returns the path to the asset. In production, this
 *   path will include the digest.
 *
 * @return {[type]} Connect middleware which will provide view helpers and precompile on requests in development
 */
middleware.assets = function() {

  if (!connectMincer) throw new Error('Please initialise connect-mincer first!');

  return function(req, res, next) {

    // add helper methods to locals so they're available in views
    res.locals.js = connectMincer.helpers.js;
    res.locals.css = connectMincer.helpers.css;
    res.locals.asset_path = connectMincer.helpers.asset_path;

    if (!connectMincer.isProduction()) {
      // if we're not in production, we should make sure all assets are precompiled
      // on a request as they won't exist otherwise. Rather than specify a list, we're
      // just precompiling all the things, though we could have the app give us a list
      // of specific things to precompile if this is too slow or whatever
      connectMincer.getEnvironment().precompile(['*', '*/**'], function(err) {
        if (err) {
          throw new Error("Something went wrong during asset precompile: " + err);
        }
        next();
      });

    } else {
      next();
    }
  };
};

/**
 * Create a Mincer.Server designed for serving assets.
 *
 * This is just an ordinary Mincer.Server, configured with the connect-mincer environment, and by
 * default is suitable for development use.
 *
 * If connect-mincer is in production mode, and a manifestFile has been provided, the server will
 * be passed the manifest data and will run in production mode (i.e. it will never compile assets,
 * and will only serve what it can find in the compiled manifest directory)
 *
 * @return {[type]}          Connect middleware which will compile and dispatch assets
 */
middleware.createServer = function() {

  if (!connectMincer) throw new Error('Please initialise connect-mincer first!');

  if (connectMincer.isProduction()) {
    // run the server in production mode by providing it with the manifest data - this will ensure
    // it never tries to compile assets
    var manifest = connectMincer.getManifest();

    if (!manifest) {
      throw new Error('Cannot run a Mincer.Server in production mode without a manifest -- please precompile assets first');
    }

    var server = new Mincer.Server(connectMincer.getEnvironment(), manifest);
  } else {
    // otherwise a normal dev server is used, which will recompile files on a request if necessary
    var server = new Mincer.Server(connectMincer.getEnvironment());
  }

  return function(req, res) {
    return server.handle(req, res);
  };
};

module.exports = function(options) {
  connectMincer.configure(options);
  return middleware;
};<commit_msg>refactored into a class<commit_after>'use strict';

var Mincer = require('mincer'),
    fs = require('fs')
;

var ConnectMincer = (function() {

  function ConnectMincer(opts) {
    this.production = opts.production === true ? true : false;
    this.options = opts;

    this._setMountPoint(opts.mountPoint);
    this._createEnvironment(opts.root, opts.paths);

    if (this.production) {
      // in production, we look up assets in the supplied manifest, so let's load that now and error
      // if it's not present, because in production mode we never compile assets on the fly
      if (fs.existsSync(opts.manifestFile)) {
        this.manifest = require(opts.manifestFile);
        if (!this.manifest || !this.manifest.assets) {
          throw new Error("Manifest file [" + opts.manifestFile + "] is not a valid manifest file");
        }
      } else {
        throw new Error("Running in production but manifest file [" + opts.manifestFile + "] not found");
      }
    }
  }

  /**
   * Sanitize and set the mount point. If no mount point was provided, it will default
   * to /assets.
   *
   * @acccess private
   * @param {[type]} mountPoint [description]
   */
  ConnectMincer.prototype._setMountPoint = function(mountPoint) {

    if (!mountPoint) {
      mountPoint = '/assets';
    } else {
      if (mountPoint.substr(0, 1) !== '/') {
        mountPoint = '/' + mountPoint;
      }
      if (mountPoint.substr(-1) === '/') {
        mountPoint = mountPoint.substr(0, mountPoint.length - 1);
      }
    }

    this.mountPoint = mountPoint;
  };

  /**
   * Create a new Mincer Environment with the provided root and paths. If the root does
   * not exist an error will be thrown. In production, this will create a cached version
   * of the environment.
   *
   * This also attaches various helpers to the environment which can be used in assets.
   *
   * @access private
   * @param  {[type]} root  [description]
   * @param  {[type]} paths [description]
   * @return {[type]}       [description]
   */
  ConnectMincer.prototype._createEnvironment = function(root, paths) {
    var self = this;

    if (!fs.existsSync(root)) {
      throw new Error("Asset root [" + root + "] does not exist");
    }

    var environment = new Mincer.Environment(root);
    paths.forEach(function(path) {
      environment.appendPath(path);
    });

    environment.registerHelper('asset_path', function(name, opts) {
      var asset = environment.findAsset(name, opts);
      if (!asset) throw new Error("File [" + name + "] not found");
      if (self.production) {
        return self._toAssetUrl(asset.digestPath);
      } else {
        return self._toAssetUrl(asset.logicalPath);
      }
    });

    if (this.production) {
      // in production we use environment.index so any future calls
      // to environment will be cached
      environment = environment.index;
    }

    this.environment = environment;
  };

  /**
   * Find all the asset paths for the provided logicalPath and returns them.
   *
   * If the logicalPath is a bundle, and the app is not in production mode, multiple paths
   * will be returned (one for each asset referenced in the bundle).
   *
   * @access private
   * @param  {[type]} logicalPath [description]
   * @param  {[type]} ext         [description]
   * @return {[type]}             [description]
   */
  ConnectMincer.prototype._findAssetPaths = function(logicalPath, ext) {
    var self = this;

    if (this.production) {
      // we're in production, and have a valid manifest, so instead of using the environment
      // we will get the digestPath directly from the manifest

      var digestPath = this.manifest.assets[logicalPath];

      if (!digestPath) {
        // this is bad, and probably means someone forgot to do compile assets before running
        // in production.
        throw new Error("Asset [" + logicalPath + "] has not been compiled");
      }

      return [this._toAssetUrl(digestPath)];
    }

    // if we're in normal development mode, we should look for the asset in our current environment
    // and return it. It should already be compiled because we force a precompile in dev mode on
    // every request.

    var asset = this.environment.findAsset(logicalPath),
        paths = []
    ;

    if (!asset) return null;

    if (this.production) {
      // in production, return the asset with its digest path
      paths.push(this._toAssetUrl(asset.digestPath));
    } else if (asset.isCompiled) {
      asset.toArray().forEach(function(a) {
        paths.push(self._toAssetUrl(a.logicalPath) + '?body=1');
      });
    }

    return paths;
  };

  ConnectMincer.prototype._toAssetUrl = function(source) {
    return this.mountPoint + '/' + source;
  };

  ConnectMincer.prototype.getHelper = function(name) {
    var self = this;

    var createTag = function(type, path, attributes) {
      var tag;

      switch (type) {
        case 'js':
          tag = "<script src='" + path + "'";
          break;
        case 'css':
          tag = "<link rel='stylesheet' href='" + path + "'";
      }

      for (var attr in attributes) {
        tag += " " + attr + "='" + attributes[attr] + "'";
      }

      switch (type) {
        case 'js':
          return tag + '></script>';
        case 'css':
          return tag + '>';
      }
    };

    switch (name) {

      case 'js':
        return function(path, attributes) {
          var paths = self._findAssetPaths(path);
          if (!paths) throw new Error('Javascript asset [' + path + '] not found');

          var tags = paths.map(function(path) {
            return createTag('js', path, attributes);
          });

          return tags.join("\n");
        };

      case 'css':
        return function(path, attributes) {
          var paths = self._findAssetPaths(path);
          if (!paths) throw new Error('CSS asset [' + path + '] not found');

          var tags = paths.map(function(path) {
            return createTag('css', path, attributes);
          });

          return tags.join("\n");
        };

      case 'asset_path':
        return function(path) {
          var paths = self._findAssetPaths(path);

          if (!paths) return '';

          if (paths.length === 1) {
            return paths[0];
          } else {
            return paths;
          }
        };
    }

    return null;
  };

  /**
   * The asset middleware.
   *
   * The asset middleware adds view helpers for loading js and css, and if in development mode
   * will also ensure assets are precompiled and route the mincer assetServer to /assetUrl
   *
   * The following helpers will be available in all views:
   *
   * - js()
   *   Accepts an asset name (e.g. 'app.js') and if found, outputs an appropriate <script> tag
   *
   * - css()
   *   Accepts an asset name (e.g. 'app.css') and if found, outputs an appropriate <link> tag
   *
   * - asset_path()
   *   Accepts an asset name (e.g. 'app.js') and returns the path to the asset. In production, this
   *   path will include the digest.
   *
   * @return {[type]} Connect middleware which will provide view helpers and precompile on requests in development
   */
  ConnectMincer.prototype.assets = function() {

    var self = this;

    return function(req, res, next) {

      // add helper methods to locals so they're available in views
      res.locals.js = self.getHelper('js');
      res.locals.css = self.getHelper('css');
      res.locals.asset_path = self.getHelper('asset_path');

      if (!self.production) {
        // if we're not in production, we should make sure all assets are precompiled
        // on a request as they won't exist otherwise. Rather than specify a list, we're
        // just precompiling all the things, though we could have the app give us a list
        // of specific things to precompile if this is too slow or whatever
        self.environment.precompile(['*', '*/**'], function(err) {
          if (err) {
            throw new Error("Something went wrong during asset precompile: " + err);
          }
          next();
        });

      } else {
        next();
      }
    };
  };

  /**
   * Create a Mincer.Server designed for serving assets.
   *
   * This is just an ordinary Mincer.Server, configured with the connect-mincer environment, and by
   * default is suitable for development use.
   *
   * If connect-mincer is in production mode, and a manifestFile has been provided, the server will
   * be passed the manifest data and will run in production mode (i.e. it will never compile assets,
   * and will only serve what it can find in the compiled manifest directory)
   *
   * @return {[type]}          Connect middleware which will compile and dispatch assets
   */
  ConnectMincer.prototype.createServer = function() {

    if (this.production) {
      // run the server in production mode by providing it with the manifest data - this will ensure
      // it never tries to compile assets

      if (!this.manifest) {
        throw new Error('Cannot run a Mincer.Server in production mode without a manifest -- please precompile assets first');
      }

      var server = new Mincer.Server(this.environment, this.manifest);
    } else {
      // otherwise a normal dev server is used, which will recompile files on a request if necessary
      var server = new Mincer.Server(this.environment);
    }

    return function(req, res) {
      return server.handle(req, res);
    };
  };

  return ConnectMincer;

})();

module.exports = ConnectMincer;<|endoftext|>


<commit_before>'use strict';
var anObject    = require('./_an-object')
  , $flags      = require('./_flags')
  , DESCRIPTORS = require('./_descriptors');
require('./es6.regexp.flags');
// 21.2.5.14 RegExp.prototype.toString()
if(require('./_fails')(function(){
  return /./.toString.call({source: 'a', flags: 'b'}) != '/a/b'
}))require('./_redefine')(RegExp.prototype, 'toString', function toString(){
  var R = anObject(this);
  return '/'.concat(R.source, '/',
    'flags' in R ? R.flags : !DESCRIPTORS && R instanceof RegExp ? $flags.call(R) : undefined);
}, true);<commit_msg>FF44- `RegExp#toString` has a wrong name<commit_after>'use strict';
require('./es6.regexp.flags');
var anObject    = require('./_an-object')
  , $flags      = require('./_flags')
  , DESCRIPTORS = require('./_descriptors')
  , TO_STRING   = 'toString'
  , $toString   = /./[TO_STRING];

var define = function(fn){
  require('./_redefine')(RegExp.prototype, TO_STRING, fn, true);
};

// 21.2.5.14 RegExp.prototype.toString()
if(require('./_fails')(function(){ return $toString.call({source: 'a', flags: 'b'}) != '/a/b'; })){
  define(function toString(){
    var R = anObject(this);
    return '/'.concat(R.source, '/',
      'flags' in R ? R.flags : !DESCRIPTORS && R instanceof RegExp ? $flags.call(R) : undefined);
  });
// FF44- RegExp#toString has a wrong name
} else if($toString.name != TO_STRING){
  define(function toString(){
    return $toString.call(this);
  });
}<|endoftext|>


<commit_before>"use strict";

var P = require('bluebird');
var util = require('util');

var hash = JSON.stringify;

/**
 * Base migration handler for unsupported schema
 */
function Unsupported(attr, current, proposed) {
    this.attr = attr;
    this.current = current;
    this.proposed = proposed;
}

Unsupported.prototype.validate = function() {
    if (hash(this.current) !== hash(this.proposed)) {
        throw new Error(this.attr + ' attribute migrations are unsupported');
    }
};

Unsupported.prototype.migrate = function() {
    return P.resolve();
};

/**
 * Table name handler
 */
function Table(db, current, proposed) {
    Unsupported.call(this, 'table', current, proposed);
}

util.inherits(Table, Unsupported);

/**
 * options object migration handler
 */
function Options(db, current, proposed) {
    Unsupported.call(this, 'options', current, proposed);
}

util.inherits(Options, Unsupported);

/**
 * attributes object migration handler
 */
function Attributes(db, current, proposed) {
    Unsupported.call(this, 'attributes', current, proposed);
}

util.inherits(Attributes, Unsupported);

/**
 * Index definition migrations
 */
function Index(db, current, proposed) {
    Unsupported.call(this, 'index', current, proposed);
}

util.inherits(Index, Unsupported);

/**
 * Secondary index definition migrations
 */
function SecondaryIndexes(db, current, proposed) {
    Unsupported.call(this, 'secondaryIndexes', current, proposed);
}

util.inherits(SecondaryIndexes, Unsupported);

/**
 * Revision retention policy definiation migrations
 */
function RevisionRetentionPolicy(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;
}

// Nothing to do; There are no constraints on moving from one (valid)
// retention policy, to another.
RevisionRetentionPolicy.prototype.validate = function() {
    return;
};

// Nothing to do.
RevisionRetentionPolicy.prototype.migrate = function() {
    this.db.log('warn/schemaMigration/revisionRetentionPolicy', 'applying', this.proposed);
    return P.resolve();
};

/**
 * Version handling
 */
function Version(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;
}

// versions must be monotonically increasing.
Version.prototype.validate = function() {
    if (this.current >= this.proposed) {
        throw new Error('new version must be higher than previous');
    }
};

Version.prototype.migrate = function() {
    this.db.log('warn/schemaMigration/version', this.current, '->', this.proposed);
    return P.resolve();
};

var migrationHandlers = {
    table: Table,
    options: Options,
    attributes: Attributes,
    index: Index,
    secondaryIndexes: SecondaryIndexes,
    revisionRetentionPolicy: RevisionRetentionPolicy,
    version: Version
};

/**
 * Schema migration.
 *
 * Accepts arguments for the current, and proposed schema as schema-info
 * objects (hint: the output of dbu#makeSchemaInfo).  Validation of the
 * proposed migration is performed, and an exception raised if necessary.
 * Note: The schemas themselves are not validated, only the migration; schema
 * input should be validated ahead of time using
 * dbu#validateAndNormalizeSchema).
 *
 * @param  {object] client; an instance of DB
 * @param  {object} schemaFrom; current schema info object.
 * @param  {object} schemaTo; proposed schema info object.
 * @throws  {Error} if the proposed migration fails to validate
 */
function SchemaMigrator(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;

    var self = this;
    this.migrators = Object.keys(migrationHandlers).map(function(key) {
        return new migrationHandlers[key](db, self.current[key], self.proposed[key]);
    });

    this._validate();
}

SchemaMigrator.prototype._validate = function() {
    this.migrators.forEach(function(migrator) {
        migrator.validate();
    });
};

/**
 * Perform any required migration tasks.
 *
 * @return a promise that resolves when the migration tasks are complete
 */
SchemaMigrator.prototype.migrate = function() {
    return P.each(this.migrators, function(migrator) {
        return migrator.migrate();
    });
};

module.exports = SchemaMigrator;
<commit_msg>use dbu#makeSchemaHash for comparisons in schemaMigrations too<commit_after>"use strict";

var dbu = require('./dbutils');
var P = require('bluebird');
var util = require('util');

var hash = dbu.makeSchemaHash;

/**
 * Base migration handler for unsupported schema
 */
function Unsupported(attr, current, proposed) {
    this.attr = attr;
    this.current = current;
    this.proposed = proposed;
}

Unsupported.prototype.validate = function() {
    if (hash(this.current) !== hash(this.proposed)) {
        throw new Error(this.attr + ' attribute migrations are unsupported');
    }
};

Unsupported.prototype.migrate = function() {
    return P.resolve();
};

/**
 * Table name handler
 */
function Table(db, current, proposed) {
    Unsupported.call(this, 'table', current, proposed);
}

util.inherits(Table, Unsupported);

/**
 * options object migration handler
 */
function Options(db, current, proposed) {
    Unsupported.call(this, 'options', current, proposed);
}

util.inherits(Options, Unsupported);

/**
 * attributes object migration handler
 */
function Attributes(db, current, proposed) {
    Unsupported.call(this, 'attributes', current, proposed);
}

util.inherits(Attributes, Unsupported);

/**
 * Index definition migrations
 */
function Index(db, current, proposed) {
    Unsupported.call(this, 'index', current, proposed);
}

util.inherits(Index, Unsupported);

/**
 * Secondary index definition migrations
 */
function SecondaryIndexes(db, current, proposed) {
    Unsupported.call(this, 'secondaryIndexes', current, proposed);
}

util.inherits(SecondaryIndexes, Unsupported);

/**
 * Revision retention policy definiation migrations
 */
function RevisionRetentionPolicy(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;
}

// Nothing to do; There are no constraints on moving from one (valid)
// retention policy, to another.
RevisionRetentionPolicy.prototype.validate = function() {
    return;
};

// Nothing to do.
RevisionRetentionPolicy.prototype.migrate = function() {
    this.db.log('warn/schemaMigration/revisionRetentionPolicy', 'applying', this.proposed);
    return P.resolve();
};

/**
 * Version handling
 */
function Version(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;
}

// versions must be monotonically increasing.
Version.prototype.validate = function() {
    if (this.current >= this.proposed) {
        throw new Error('new version must be higher than previous');
    }
};

Version.prototype.migrate = function() {
    this.db.log('warn/schemaMigration/version', this.current, '->', this.proposed);
    return P.resolve();
};

var migrationHandlers = {
    table: Table,
    options: Options,
    attributes: Attributes,
    index: Index,
    secondaryIndexes: SecondaryIndexes,
    revisionRetentionPolicy: RevisionRetentionPolicy,
    version: Version
};

/**
 * Schema migration.
 *
 * Accepts arguments for the current, and proposed schema as schema-info
 * objects (hint: the output of dbu#makeSchemaInfo).  Validation of the
 * proposed migration is performed, and an exception raised if necessary.
 * Note: The schemas themselves are not validated, only the migration; schema
 * input should be validated ahead of time using
 * dbu#validateAndNormalizeSchema).
 *
 * @param  {object] client; an instance of DB
 * @param  {object} schemaFrom; current schema info object.
 * @param  {object} schemaTo; proposed schema info object.
 * @throws  {Error} if the proposed migration fails to validate
 */
function SchemaMigrator(db, current, proposed) {
    this.db = db;
    this.current = current;
    this.proposed = proposed;

    var self = this;
    this.migrators = Object.keys(migrationHandlers).map(function(key) {
        return new migrationHandlers[key](db, self.current[key], self.proposed[key]);
    });

    this._validate();
}

SchemaMigrator.prototype._validate = function() {
    this.migrators.forEach(function(migrator) {
        migrator.validate();
    });
};

/**
 * Perform any required migration tasks.
 *
 * @return a promise that resolves when the migration tasks are complete
 */
SchemaMigrator.prototype.migrate = function() {
    return P.each(this.migrators, function(migrator) {
        return migrator.migrate();
    });
};

module.exports = SchemaMigrator;
<|endoftext|>


<commit_before>define(['dispatcher'], function(dispatcher) {

	"use strict";

	var items = {}

	var idName = 'input-id-';
	var idNum  = 1;

	var _add = function(items, element) {
		var id = element.getAttribute('data-id');

		element.addEventListener('focus', function() {
			element.parentNode.classList.remove('error');
			element.parentNode.classList.add('focus');
		}, false);
		element.addEventListener('blur', function() {
			element.parentNode.classList.remove('focus');
		}, false);

		element.addEventListener('keyup', function() {
			if (element.value) {
				element.parentNode.classList.add('not-empty');
			} else {
				element.parentNode.classList.remove('not-empty');
			}
		}, false);

		if (!id) {
			id = idName + idNum;
			idNum++;
		}

		items[id] = {
			id: id,
			element: element
		}
	}

	var _remove = function(items, item) {
		delete items[item.id];
	}

	var _handleMutate = function() {
		var elements;

		var check = function(items, element) {
			var found = false;
			for (var id in items) {
				if (items.hasOwnProperty(id)) {
					if (items[id].element === element) {
						found = true;
						break;
					}
				}
			}
			if (!found) {
				_add(items, element);
			}
		}

		var backCheck = function(items, elements, item) {
			var element = item.element;
			var found   = false;

			for (var i = 0; i < elements.length; i++) {
				if (elements[i] === item.element) {
					found = true;
					break;
				}
			}

			if (!found) {
				_remove(items, item);
			}
		}

		var inputs = Array.prototype.slice.call(document.getElementsByTagName('input'));
		var textareas = Array.prototype.slice.call(document.getElementsByTagName('textarea'));

		elements = inputs.concat(textareas);
		for (var i = 0; i < elements.length; i++) {
			check(items, elements[i]);
		}
		for (var id in items) {
			if (items.hasOwnProperty(id)) {
				backCheck(items, elements, items[id]);
			}
		}
	}

	var init = function() {
		_handleMutate();

		dispatcher.subscribe(function(e) {
			if (e.type === 'mutate') {
				_handleMutate();
			}
		});
	}

	return {
		init: init
	}
});<commit_msg>firefox hotfix<commit_after>define(['dispatcher'], function(dispatcher) {

	"use strict";

	var items = {}

	var idName = 'input-id-';
	var idNum  = 1;

	var _add = function(items, element) {
		var id = element.getAttribute('data-id');

		if (element.value) {
			element.parentNode.classList.add('not-empty');
		} else {
			element.parentNode.classList.remove('not-empty');
		}

		element.addEventListener('focus', function() {
			element.parentNode.classList.remove('error');
			element.parentNode.classList.add('focus');
		}, false);
		element.addEventListener('blur', function() {
			element.parentNode.classList.remove('focus');
		}, false);

		element.addEventListener('keyup', function() {
			if (element.value) {
				element.parentNode.classList.add('not-empty');
			} else {
				element.parentNode.classList.remove('not-empty');
			}
		}, false);

		if (!id) {
			id = idName + idNum;
			idNum++;
		}

		items[id] = {
			id: id,
			element: element
		}
	}

	var _remove = function(items, item) {
		delete items[item.id];
	}

	var _handleMutate = function() {
		var elements;

		var check = function(items, element) {
			var found = false;
			for (var id in items) {
				if (items.hasOwnProperty(id)) {
					if (items[id].element === element) {
						found = true;
						break;
					}
				}
			}
			if (!found) {
				_add(items, element);
			}
		}

		var backCheck = function(items, elements, item) {
			var element = item.element;
			var found   = false;

			for (var i = 0; i < elements.length; i++) {
				if (elements[i] === item.element) {
					found = true;
					break;
				}
			}

			if (!found) {
				_remove(items, item);
			}
		}

		var inputs = Array.prototype.slice.call(document.getElementsByTagName('input'));
		var textareas = Array.prototype.slice.call(document.getElementsByTagName('textarea'));

		elements = inputs.concat(textareas);
		for (var i = 0; i < elements.length; i++) {
			check(items, elements[i]);
		}
		for (var id in items) {
			if (items.hasOwnProperty(id)) {
				backCheck(items, elements, items[id]);
			}
		}
	}

	var init = function() {
		_handleMutate();

		dispatcher.subscribe(function(e) {
			if (e.type === 'mutate') {
				_handleMutate();
			}
		});
	}

	return {
		init: init
	}
});<|endoftext|>


<commit_before>function CanvasFS(cfsEl) {

    cfsEl.cfsSetData = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetData() passed something other than Uint8ClampedArray');
        }
        var prepped = this.cfsPrepArr(d);
        var ctx = this.getContext('2d');
        var s = Math.ceil(Math.sqrt(prepped.byteLength / 4));
        console.log('cfsSetData() using square side length %d', s);
        this.setAttribute('width', s);
        this.setAttribute('height', s);
        var idata = ctx.createImageData(s, s);
        idata.data.set(prepped);
        ctx.putImageData(idata, 0, 0);
        return idata;
    };

    cfsEl.cfsGetData = function() {
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var arr = new Array();
        for (var i = 3 ; i < raw.length ; i += 4) {
            if (raw[i] == 0) {  //bail when alpha value is zero
                i = raw.length + 1;
            } else {
                for (var j = 0 ; j < 3 ; j++) {
                    arr.push(raw[i - 3 + j]);
                }
            }
        }
        return new Uint8ClampedArray(arr);
    };

    //this uses a two-byte length encoding in first two bytes... sorry if you want longer. :)
    cfsEl.cfsSetSteg = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetSteg() passed something other than string or Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var id = 0;
        for (var i = -2 ; i < d.length; i++) {
            for (var b = 7 ; b >= 0 ; b--) {
                if (id >= idata.data.length) {
                    console.warn('cfsSetSteg(): ran out of space in image, truncated input at i=' + i);
                    ctx.putImageData(idata, 0, 0);
                    return i;
                } else {
                    var by;
                    if (i == -2) {
                        by = d.length >> 8;
                    } else if (i == -1) {
                        by = d.length & 0x00FF;
                    } else {
                        by = d[i];
                    }
                    if (by & (1 << b)) {
                        idata.data[id] = idata.data[id] | 1;
                    } else {
                        idata.data[id] = idata.data[id] & 0xFE;
                    }
                    //console.info('d[%d] => %d   %d.%d => %d', i, by, id, b, idata.data[id]);
                    id++;
                    if (id % 4 == 3) id++;  //skip alpha
                }
            }
        }
        ctx.putImageData(idata, 0, 0);
        console.info('cfsSetSteg() wrote %d bytes into %d bytes of imagedata', d.length, id);
        return d.length;
    };

    cfsEl.cfsGetSteg = function() {
        var arr = new Array()
        var len = 0;
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var b = 7;
        var by = 0;
        var byteCount = -2;
        for (var i = 0 ; i < raw.length ; i++) {
            if ((byteCount > 0) && (byteCount > len - 1)) {
                console.info('cfsGetSteg() successfully reached len=%d', len);
                //console.info('reached len=%d, arr => %o', len, arr);
                return new Uint8ClampedArray(arr);
            }
            if (i % 4 == 3) continue;
            by = by | ((raw[i] & 1) << b);
            //console.info('[%i>%i] by[%d/%d]=%o (raw[i] & 1 = %o)', i, raw[i], byteCount, len, by, (raw[i] & 1));
            b--;
            if (b < 0) {
                //console.log('[%d/%d] got all bits to make by=%o', byteCount, len, by);
                if (byteCount == -2) {
                    len = by << 8;
                    console.info('  len[0] -> %d', len);
                } else if (byteCount == -1) {
                    len = len | by;
                    console.info('  len[1] -> %d', len);
                } else {
                    arr.push(by);
                }
                by = 0;
                b = 7;
                byteCount++;
            }
        }
        console.warn('cfsGetSteg() fell thru to bottom of cfsGetSteg(); possible weird length problem');
        return new Uint8ClampedArray(arr);
    };

    //this takes "raw" data (Uint8ClampedArray) and pads it out to skip the alpha bytes. it also does some other
    //  work, like puts in the end byte (which has alpha = 0)
    cfsEl.cfsPrepArr = function(arr) {
        if (!(arr instanceof Uint8ClampedArray)) {
            console.error('cfsPrepArr() passed something other than string or Uint8ClampedArray');
        }
        var a = new Array();
        var b = 0;
        //console.info('%o %d -> %d', arr, arr.length, Math.ceil(arr.length / 4) * 4);
        for (var i = 0 ; i < (Math.ceil(arr.length / 3) * 4) ; i++) {
            if (i % 4 == 3) {  //alpha byte
                a[i] = 255;
                continue;
            }
            a[i] = arr[b] || 0;
            b++;
        }
        a.push(0, 0, 0, 0);
        return new Uint8ClampedArray(a);
    };

///////// some utilities (mostly string conversion)

/* note, there are better (utf8) solutions here: http://stackoverflow.com/q/6965107 (just too lazy to do now) */

    cfsEl.cfsStringToArr = function(str) {
        var a = new Array();
        for (var i = 0 ; i < str.length ; i++) {
            a.push(str.charCodeAt(i));
        }
        return new Uint8ClampedArray(a);
    };

    cfsEl.cfsArrToString = function(buf) {
        return String.fromCharCode.apply(null, new Uint8ClampedArray(buf));
    };

}

<commit_msg>cleanup and fixes<commit_after>function CanvasFS(cfsEl) {

    cfsEl.cfsSetData = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetData() passed something other than Uint8ClampedArray');
        }
        var prepped = this.cfsPrepArr(d);
        var ctx = this.getContext('2d');
        var s = Math.ceil(Math.sqrt(prepped.byteLength / 4));
        console.log('cfsSetData() using square side length %d', s);
        this.setAttribute('width', s);
        this.setAttribute('height', s);
        var idata = ctx.createImageData(s, s);
        idata.data.set(prepped);
        ctx.putImageData(idata, 0, 0);
        return idata;
    };

    cfsEl.cfsGetData = function() {
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        return this.cfsUnprepArr(idata.data);
    };

    //this uses a two-byte length encoding in first two bytes... sorry if you want longer. :)
    cfsEl.cfsSetSteg = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetSteg() passed something other than Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var id = 0;
        for (var i = -2 ; i < d.length; i++) {
            for (var b = 7 ; b >= 0 ; b--) {
                if (id >= idata.data.length) {
                    console.warn('cfsSetSteg(): ran out of space in image, truncated input at i=' + i);
                    ctx.putImageData(idata, 0, 0);
                    return i;
                } else {
                    var by;
                    if (i == -2) {
                        by = d.length >> 8;
                    } else if (i == -1) {
                        by = d.length & 0x00FF;
                    } else {
                        by = d[i];
                    }
                    if (by & (1 << b)) {
                        idata.data[id] = idata.data[id] | 1;
                    } else {
                        idata.data[id] = idata.data[id] & 0xFE;
                    }
                    //console.info('d[%d] => %d   %d.%d => %d', i, by, id, b, idata.data[id]);
                    id++;
                    if (id % 4 == 3) id++;  //skip alpha
                }
            }
        }
        ctx.putImageData(idata, 0, 0);
        console.info('cfsSetSteg() wrote %d bytes into %d bytes of imagedata', d.length, id);
        return d.length;
    };

    cfsEl.cfsGetSteg = function() {
        var arr = new Array()
        var len = 0;
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var b = 7;
        var by = 0;
        var byteCount = -2;
        for (var i = 0 ; i < raw.length ; i++) {
            if ((byteCount > 0) && (byteCount > len - 1)) {
                console.info('cfsGetSteg() successfully reached len=%d', len);
                //console.info('reached len=%d, arr => %o', len, arr);
                return new Uint8ClampedArray(arr);
            }
            if (i % 4 == 3) continue;
            by = by | ((raw[i] & 1) << b);
            //console.info('[%i>%i] by[%d/%d]=%o (raw[i] & 1 = %o)', i, raw[i], byteCount, len, by, (raw[i] & 1));
            b--;
            if (b < 0) {
                //console.log('[%d/%d] got all bits to make by=%o', byteCount, len, by);
                if (byteCount == -2) {
                    len = by << 8;
                    console.info('  len[0] -> %d', len);
                } else if (byteCount == -1) {
                    len = len | by;
                    console.info('  len[1] -> %d', len);
                } else {
                    arr.push(by);
                }
                by = 0;
                b = 7;
                byteCount++;
            }
        }
        console.warn('cfsGetSteg() fell thru to bottom of cfsGetSteg(); possible weird length problem');
        return new Uint8ClampedArray(arr);
    };

    //this takes "raw" data (Uint8ClampedArray) and pads it out to skip the alpha bytes. it also does some other
    //  work, like puts in the end byte (which has alpha = 0)
    cfsEl.cfsPrepArr = function(arr) {
        if (!(arr instanceof Uint8ClampedArray)) {
            console.error('cfsPrepArr() passed something other than Uint8ClampedArray');
        }
        var a = new Array();
        var b = 0;
        //console.info('%o %d -> %d', arr, arr.length, Math.ceil(arr.length / 4) * 4);
        for (var i = 0 ; i < (Math.ceil(arr.length / 3) * 4) ; i++) {
            if (i % 4 == 3) {  //alpha byte
                a[i] = 255;
                continue;
            }
            a[i] = arr[b] || 0;
            b++;
        }
        a.push(0, 0, 0, 0);
        return new Uint8ClampedArray(a);
    };

    //inverse of above, basically. takes raw pixel data and finds our data
    cfsEl.cfsUnprepArr = function(arr) {
        if (!(arr instanceof Uint8ClampedArray)) {
            console.error('cfsUnrepArr() passed something other than Uint8ClampedArray');
        }
        var a = new Array();
        for (var i = 3 ; i < arr.length ; i += 4) {  //i is the alpha byte: 3, 7, etc..
            if (arr[i] == 0) {  //bail when alpha value is zero
                i = arr.length + 1;
            } else {
                for (var j = 0 ; j < 3 ; j++) { //here is where we may pad out unwanted 0x00 for GB or B bytes on final pixel. :( TODO
                    a.push(arr[i - 3 + j]);
                }
            }
        }
        return new Uint8ClampedArray(a);
    };

///////// some utilities (mostly string conversion)

/* note, there are better (utf8) solutions here: http://stackoverflow.com/q/6965107 (just too lazy to do now) */

    cfsEl.cfsStringToArr = function(str) {
        var a = new Array();
        for (var i = 0 ; i < str.length ; i++) {
            a.push(str.charCodeAt(i));
        }
        return new Uint8ClampedArray(a);
    };

    cfsEl.cfsArrToString = function(buf) {
        return String.fromCharCode.apply(null, new Uint8ClampedArray(buf));
    };

}

<|endoftext|>


<commit_before>var util = require('util');
var Filterer = require('./Filterer');

/**
 * @typedef {Object} module:py-logging.LogRecord
 * @property {number} created Time when this record was created.
 * @property {string} name Name of the logger.
 * @property {number} levelno Numeric logging level.
 * @property {string} levelname Text logging level.
 * @property {string} message The logged message.
 * @property {Object} [error] The logged error.
 * @property {Object} [extra] Extra data.
 * @property {number} [pid] Process ID (if available).
 * @property {string} [processtitle] Process title (if available).
 */

/**
 * @constructor Logger
 * @extends Filterer
 * @param {Object} manager
 * @param {Object} parent
 * @param {string} name
 * @param {number} [level]
 */
function Logger(manager, parent, name, level) {
	level = level || Logger.NOTSET;

	if (Logger.getLevelName(level) === '') {
		throw new Error('Argument 4 of Logger.constructor has unsupported value'
			+ ' \'' + level + '\'');
	}

	Filterer.call(this);

	/**
	 * Instance of manager, which holds the hierarchy of loggers.
	 *
	 * @private
	 * @type {Object}
	 */
	this._manager = manager;

	/**
	 * Parent logger.
	 *
	 * @private
	 * @type {Object}
	 */
	this._parent = parent;

	/**
	 * Name of this logger.
	 *
	 * @private
	 * @type {string}
	 */
	this._name = name;

	/**
	 * The threshold for this logger.
	 *
	 * @private
	 * @type {number}
	 */
	this._level = level;

	/**
	 * Array of set handlers.
	 *
	 * @private
	 * @type {Array}
	 */
	this._handlers = [];

	/**
	 * If this evaluates to true, events logged to this logger will be ignored.
	 *
	 * @memberof Logger.prototype
	 * @type {boolean}
	 */
	this.disabled = false;

	/**
	 * If this evaluates to true, events logged to this logger will be passed
	 * to the handlers of higher level loggers.
	 *
	 * @memberof Logger.prototype
	 * @type {boolean}
	 */
	this.propagate = true;
}
util.inherits(Logger, Filterer);

Logger.NOTSET   = 0;
Logger.DEBUG    = 10;
Logger.INFO     = 20;
Logger.WARNING  = 30;
Logger.ERROR    = 40;
Logger.CRITICAL = 50;

/**
 * Return the textual representation of logging level.
 *
 * @static
 * @param  {number} level
 * @return {string}
 */
Logger.getLevelName = function(level) {
	var levelName = '';

	if (level === Logger.DEBUG) {
		levelName = 'DEBUG';
	} else if (level === Logger.INFO) {
		levelName = 'INFO';
	} else if (level === Logger.WARNING) {
		levelName = 'WARNING';
	} else if (level === Logger.ERROR) {
		levelName = 'ERROR';
	} else if (level === Logger.CRITICAL) {
		levelName = 'CRITICAL';
	} else if (level === Logger.NOTSET) {
		levelName = 'NOTSET';
	}

	return levelName;
};

/**
 * Return value of the level name.
 *
 * @static
 * @param  {string} levelName
 * @return {number}
 */
Logger.getLevelByName = function(levelName) {
	var level = '';

	if (levelName === 'DEBUG') {
		level = Logger.DEBUG;
	} else if (levelName === 'INFO') {
		level = Logger.INFO;
	} else if (levelName === 'WARNING') {
		level = Logger.WARNING;
	} else if (levelName === 'ERROR') {
		level = Logger.ERROR;
	} else if (levelName === 'CRITICAL') {
		level = Logger.CRITICAL;
	} else if (levelName === 'NOTSET') {
		level = Logger.NOTSET;
	}

	return level;
};

/**
 * Return the text representation of this logger.
 *
 * @return {string}
 */
Logger.prototype.toString = function() {
	return '[object Logger <' + this._name + '>]';
};

/**
 * Return the name of this logger.
 *
 * @return {string}
 */
Logger.prototype.getName = function() {
	return this._name;
};

/**
 * Return a logger which is a descendant to this one.
 *
 * @param  {string} suffix
 * @return {Object}
 */
Logger.prototype.getChild = function(suffix) {
	if (!suffix) {
		throw new Error('Argument 1 of Logger.getChild is not specified.');
	}
	var base = this._name === 'root' ? '' : this._name + '.';
	return this._manager.getLogger(base + suffix);
};

/**
 * Return the effective level for this logger.
 *
 * @return {number}
 */
Logger.prototype.getEffectiveLevel = function() {
	var logger = this;

	while (logger) {
		if (logger._level) {
			return logger._level;
		}
		logger = logger._parent;
	}

	return Logger.NOTSET;
};

/**
 * Is this logger enabled for specified level?
 *
 * @param  {number}  level
 * @return {boolean}
 */
Logger.prototype.isEnabledFor = function(level) {
	return level >= this.getEffectiveLevel();
};

/**
 * Set the logging level of this logger.
 *
 * @param {number} level
 */
Logger.prototype.setLevel = function(level) {
	if (Logger.getLevelName(level) === '') {
		throw new Error('Argument 1 of Logger.setLevel has unsupported value'
			+ ' \'' + level + '\'');
	}

	this._level = level;
};

/**
 * Add the specified handler to this logger.
 *
 * @param {Handler} handler
 */
Logger.prototype.addHandler = function(handler) {
	if (typeof handler !== 'object') {
		throw new Error('Argument 1 of Logger.addHandler is not an object.');
	}

	this._handlers.push(handler);
};

/**
 * Remove the specified handler from this logger.
 *
 * @param  {Handler} handler
 */
Logger.prototype.removeHandler = function(handler) {
	var index = this._handlers.indexOf(handler);
	if (index > -1) {
		this._handlers.splice(index, 1);
	}
};

/**
 * See if this logger has any handlers configured.
 *
 * @return {boolean}
 */
Logger.prototype.hasHandlers = function() {
	var logger = this;

	while (logger) {
		if (logger._handlers.length) {
			return true;
		}

		if (logger.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}

	return false;
};

/**
 * Log msg with severity 'DEBUG'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.debug = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.DEBUG)) {
		this._log(Logger.DEBUG, msg, error, extra);
	}
};

/**
 * Log msg with severity 'INFO'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.info = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.INFO)) {
		this._log(Logger.INFO, msg, error, extra);
	}
};

/**
 * Log msg with severity 'WARNING'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.warning = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.WARNING)) {
		this._log(Logger.WARNING, msg, error, extra);
	}
};

/**
 * Log msg with severity 'ERROR'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.error = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.ERROR)) {
		this._log(Logger.ERROR, msg, error, extra);
	}
};

/**
 * Log msg with severity 'CRITICAL'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.critical = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.CRITICAL)) {
		this._log(Logger.CRITICAL, msg, error, extra);
	}
};

/**
 * Log msg with specified severity.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.log = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(level)) {
		this._log(level, msg, error, extra);
	}
};

/**
 * Create a LogRecord object.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 * @return {module:py-logging.LogRecord}
 */
Logger.prototype.makeRecord = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	var record = {
		created: Date.now(),
		name: this._name,
		levelno: level,
		levelname: Logger.getLevelName(level),
		message: msg
	};
	if (typeof global === 'object' && global.process && global.process.pid) {
		record.pid = global.process.pid;
		record.processtitle = global.process.title;
	}
	if (error) {
		record.error = error;
	}
	if (extra) {
		record = Object.assign(record, extra);
	}

	return record;
};

/**
 * @private
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype._log = function(level, msg, error, extra) {
	var record = this.makeRecord(level, msg, error, extra);

	if (!this.disabled && this.filter(record)) {
		this._callHandlers(record);
	}
};

/**
 * @private
 * @param  {module:py-logging.LogRecord} record
 */
Logger.prototype._callHandlers = function(record) {
	var logger = this;

	while (logger) {
		logger._handlers.forEach(function(handler) {
			if (handler.isEnabledFor(record.levelno)) {
				handler.handle(record);
			}
		});

		if (logger.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}
};

module.exports = Logger;
<commit_msg>#11 pid -> process, processtitle -> processName<commit_after>var util = require('util');
var Filterer = require('./Filterer');

/**
 * @typedef {Object} module:py-logging.LogRecord
 * @property {number} created Time when this record was created.
 * @property {string} name Name of the logger.
 * @property {number} levelno Numeric logging level.
 * @property {string} levelname Text logging level.
 * @property {string} message The logged message.
 * @property {Object} [error] The logged error.
 * @property {Object} [extra] Extra data.
 * @property {number} [process] Process ID (if available).
 * @property {string} [processName] Process title (if available).
 */

/**
 * @constructor Logger
 * @extends Filterer
 * @param {Object} manager
 * @param {Object} parent
 * @param {string} name
 * @param {number} [level]
 */
function Logger(manager, parent, name, level) {
	level = level || Logger.NOTSET;

	if (Logger.getLevelName(level) === '') {
		throw new Error('Argument 4 of Logger.constructor has unsupported value'
			+ ' \'' + level + '\'');
	}

	Filterer.call(this);

	/**
	 * Instance of manager, which holds the hierarchy of loggers.
	 *
	 * @private
	 * @type {Object}
	 */
	this._manager = manager;

	/**
	 * Parent logger.
	 *
	 * @private
	 * @type {Object}
	 */
	this._parent = parent;

	/**
	 * Name of this logger.
	 *
	 * @private
	 * @type {string}
	 */
	this._name = name;

	/**
	 * The threshold for this logger.
	 *
	 * @private
	 * @type {number}
	 */
	this._level = level;

	/**
	 * Array of set handlers.
	 *
	 * @private
	 * @type {Array}
	 */
	this._handlers = [];

	/**
	 * If this evaluates to true, events logged to this logger will be ignored.
	 *
	 * @memberof Logger.prototype
	 * @type {boolean}
	 */
	this.disabled = false;

	/**
	 * If this evaluates to true, events logged to this logger will be passed
	 * to the handlers of higher level loggers.
	 *
	 * @memberof Logger.prototype
	 * @type {boolean}
	 */
	this.propagate = true;
}
util.inherits(Logger, Filterer);

Logger.NOTSET   = 0;
Logger.DEBUG    = 10;
Logger.INFO     = 20;
Logger.WARNING  = 30;
Logger.ERROR    = 40;
Logger.CRITICAL = 50;

/**
 * Return the textual representation of logging level.
 *
 * @static
 * @param  {number} level
 * @return {string}
 */
Logger.getLevelName = function(level) {
	var levelName = '';

	if (level === Logger.DEBUG) {
		levelName = 'DEBUG';
	} else if (level === Logger.INFO) {
		levelName = 'INFO';
	} else if (level === Logger.WARNING) {
		levelName = 'WARNING';
	} else if (level === Logger.ERROR) {
		levelName = 'ERROR';
	} else if (level === Logger.CRITICAL) {
		levelName = 'CRITICAL';
	} else if (level === Logger.NOTSET) {
		levelName = 'NOTSET';
	}

	return levelName;
};

/**
 * Return value of the level name.
 *
 * @static
 * @param  {string} levelName
 * @return {number}
 */
Logger.getLevelByName = function(levelName) {
	var level = '';

	if (levelName === 'DEBUG') {
		level = Logger.DEBUG;
	} else if (levelName === 'INFO') {
		level = Logger.INFO;
	} else if (levelName === 'WARNING') {
		level = Logger.WARNING;
	} else if (levelName === 'ERROR') {
		level = Logger.ERROR;
	} else if (levelName === 'CRITICAL') {
		level = Logger.CRITICAL;
	} else if (levelName === 'NOTSET') {
		level = Logger.NOTSET;
	}

	return level;
};

/**
 * Return the text representation of this logger.
 *
 * @return {string}
 */
Logger.prototype.toString = function() {
	return '[object Logger <' + this._name + '>]';
};

/**
 * Return the name of this logger.
 *
 * @return {string}
 */
Logger.prototype.getName = function() {
	return this._name;
};

/**
 * Return a logger which is a descendant to this one.
 *
 * @param  {string} suffix
 * @return {Object}
 */
Logger.prototype.getChild = function(suffix) {
	if (!suffix) {
		throw new Error('Argument 1 of Logger.getChild is not specified.');
	}
	var base = this._name === 'root' ? '' : this._name + '.';
	return this._manager.getLogger(base + suffix);
};

/**
 * Return the effective level for this logger.
 *
 * @return {number}
 */
Logger.prototype.getEffectiveLevel = function() {
	var logger = this;

	while (logger) {
		if (logger._level) {
			return logger._level;
		}
		logger = logger._parent;
	}

	return Logger.NOTSET;
};

/**
 * Is this logger enabled for specified level?
 *
 * @param  {number}  level
 * @return {boolean}
 */
Logger.prototype.isEnabledFor = function(level) {
	return level >= this.getEffectiveLevel();
};

/**
 * Set the logging level of this logger.
 *
 * @param {number} level
 */
Logger.prototype.setLevel = function(level) {
	if (Logger.getLevelName(level) === '') {
		throw new Error('Argument 1 of Logger.setLevel has unsupported value'
			+ ' \'' + level + '\'');
	}

	this._level = level;
};

/**
 * Add the specified handler to this logger.
 *
 * @param {Handler} handler
 */
Logger.prototype.addHandler = function(handler) {
	if (typeof handler !== 'object') {
		throw new Error('Argument 1 of Logger.addHandler is not an object.');
	}

	this._handlers.push(handler);
};

/**
 * Remove the specified handler from this logger.
 *
 * @param  {Handler} handler
 */
Logger.prototype.removeHandler = function(handler) {
	var index = this._handlers.indexOf(handler);
	if (index > -1) {
		this._handlers.splice(index, 1);
	}
};

/**
 * See if this logger has any handlers configured.
 *
 * @return {boolean}
 */
Logger.prototype.hasHandlers = function() {
	var logger = this;

	while (logger) {
		if (logger._handlers.length) {
			return true;
		}

		if (logger.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}

	return false;
};

/**
 * Log msg with severity 'DEBUG'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.debug = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.DEBUG)) {
		this._log(Logger.DEBUG, msg, error, extra);
	}
};

/**
 * Log msg with severity 'INFO'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.info = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.INFO)) {
		this._log(Logger.INFO, msg, error, extra);
	}
};

/**
 * Log msg with severity 'WARNING'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.warning = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.WARNING)) {
		this._log(Logger.WARNING, msg, error, extra);
	}
};

/**
 * Log msg with severity 'ERROR'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.error = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.ERROR)) {
		this._log(Logger.ERROR, msg, error, extra);
	}
};

/**
 * Log msg with severity 'CRITICAL'.
 *
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.critical = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(Logger.CRITICAL)) {
		this._log(Logger.CRITICAL, msg, error, extra);
	}
};

/**
 * Log msg with specified severity.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype.log = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	if (this.isEnabledFor(level)) {
		this._log(level, msg, error, extra);
	}
};

/**
 * Create a LogRecord object.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 * @return {module:py-logging.LogRecord}
 */
Logger.prototype.makeRecord = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	var record = {
		created: Date.now(),
		name: this._name,
		levelno: level,
		levelname: Logger.getLevelName(level),
		message: msg
	};
	if (typeof global === 'object' && global.process && global.process.pid) {
		record.process = global.process.pid;
		record.processName = global.process.title;
	}
	if (error) {
		record.error = error;
	}
	if (extra) {
		record = Object.assign(record, extra);
	}

	return record;
};

/**
 * @private
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object} [error]
 * @param  {Object} [extra]
 */
Logger.prototype._log = function(level, msg, error, extra) {
	var record = this.makeRecord(level, msg, error, extra);

	if (!this.disabled && this.filter(record)) {
		this._callHandlers(record);
	}
};

/**
 * @private
 * @param  {module:py-logging.LogRecord} record
 */
Logger.prototype._callHandlers = function(record) {
	var logger = this;

	while (logger) {
		logger._handlers.forEach(function(handler) {
			if (handler.isEnabledFor(record.levelno)) {
				handler.handle(record);
			}
		});

		if (logger.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}
};

module.exports = Logger;
<|endoftext|>


<commit_before>var Suite = require('./Suite')
  , Test = require('./Test')
  , EventEmitter = require('events').EventEmitter
  , util = require('util')
  , path = require('path')
  , Date = global.Date

/**
 * Creates a new PPUnit object
 *
 * @constructor
 */
var PPUnit = function (options) {
    var self = this

    PPUnit.super_.call(self)

    options = options || {}
    self.concurrency = options.concurrency || -1

    self.rootSuite = new Suite(undefined)
    self.rootSuite.timeout(2000)
    self.rootSuite.globallyExclusive()
    self.rootSuite.locallyExclusiveTests()

    self.allTests = []
    self.failures = []
    self.tickId = 0

    self.stats = {
        suites: 0
      , tests: 0
      , skipped: 0
      , passes: 0
      , failures: 0
      , completed: 0
      , startTime: 0
      , maxConcurrency: 0
      , currentlyRunning: 0
      , end: undefined
      , duration: undefined
    }

    self._queue = []
    self._nextId = 1
    self._files = []
    self._bailing = false

    process.on('SIGINT', function () {
        self._bail()
    })
}

util.inherits(PPUnit, EventEmitter)
module.exports = PPUnit

/**
 * Adds a file that contains tests to be run
 *
 * @param {String} file Path to the file
 */
PPUnit.prototype.addFile = function (file) {
    this._files.push(path.resolve(file))
}

/**
 * Runs the test suites
 *
 * @param {function} callback A function to call after finish is emitted
 */
PPUnit.prototype.run = function (callback) {
    this._loadFiles()

    var self = this

    self.rootSuite.on('test', function (test) {
        self._addTest(test)
    })

    self.rootSuite.on('suite', function (suite) {
        suite.id = self._nextId++
    })

    self.rootSuite.prepare()

    self.stats.startTime = new Date
    self.emit('start')

    self.allTests[self.allTests.length - 1].on('finish', function () {
        self.stats.end = new Date
        self.stats.duration = new Date - self.stats.startTime

        self.emit('finish')
        callback()
    })

    self._queue.push(self.allTests[0])
    self._nextTest()
}

/**
 * Loads/requires the files and builds the test suites
 *
 * @private
 */
PPUnit.prototype._loadFiles = function () {
    var self = this

    self._files.forEach(function (file) {
        //TODO: Emit pre-require and require
        require(file)
    })
}

/**
 * Adds a test to the list and wires up events
 *
 * @param {Test} newTest The test to add
 */
PPUnit.prototype._addTest = function (newTest) {
    var self = this

    newTest.id = this._nextId++
    if (newTest.type !== Test.TYPE.ROOT) {
        self.stats.tests++
    }

    newTest.on('ready', function () {
        if (self._bailing) {
            return
        }

        self._queue.push(newTest)
        self._nextTest()
    })

    newTest.on('start', function () {
        self.emit('test start', newTest)
    })

    newTest.on('finish', function (previous) {
        if (!previous) {
            newTest.tickEnd = ++self.tickId
            self.stats.currentlyRunning--
        }

        if (newTest.type !== Test.TYPE.ROOT) {
            if (!newTest.completedNumber) {
                newTest.completedNumber = ++self.stats.completed
            }

            switch (newTest.result) {
                case Test.RESULT.SUCCESS:
                    self.stats.passes++
                    break

                case Test.RESULT.HOOK_FAILURE:
                case Test.RESULT.TIMEOUT:
                case Test.RESULT.FAILURE:
                    if (previous && previous.result === Test.RESULT.SUCCESS) {
                        self.stats.passes--
                    }

                    if (!previous || previous.result === Test.RESULT.SUCCESS) {
                        self.failures.push(newTest)
                        self.stats.failures++
                        newTest.failureNumber = self.stats.failures
                    }

                    break

                case Test.RESULT.SKIPPED:
                    self.stats.skipped++
                    break
            }
        }

        self.emit('test finish', newTest, previous)
        self._nextTest()
    })

    if (newTest.exclusivity === Test.EXCLUSIVITY.GLOBAL) {
        var edges = []

        this.allTests.forEach(function (test) {
            if (test.nextTests.length) {
                return
            }

            edges.push(test)
        })

        newTest.addPriorTests(edges)
    }

    this.allTests.push(newTest)
}

/**
 * Attempts to run the next ready test
 * Depending on the concurrency limit, many tests may be running at the same time
 *
 * @private
 */
PPUnit.prototype._nextTest = function () {
    var self = this
    process.nextTick(function () {
        if (self._queue.length > 0 && (self.concurrency < 1 || self.stats.currentlyRunning < self.concurrency)) {
            var test = self._queue.shift()
            test.tickStart = self.tickId++
            self.stats.currentlyRunning++
            self.stats.maxConcurrency = Math.max(self.stats.maxConcurrency, self.stats.currentlyRunning)

            test.run()

            self._nextTest()
        }
    })
}

/**
 * Stops the run and marks remaining tests as skipped
 *
 * @private
 */
PPUnit.prototype._bail = function () {
    var self = this
    self._bailing = true
    self._queue = []

    self.allTests.forEach(function (test, index) {
        if (test.state === Test.STATE.COMPLETED || index === (self.allTests.length - 1)) {
            return
        }

        if (test.type !== Test.TYPE.ROOT) {
            test.complete(void 0, Test.RESULT.SKIPPED)
        } else {
            test.complete(void 0, Test.RESULT.SUCCESS)
        }
    })

    self._queue.push(self.allTests[self.allTests.length - 1])
    self._nextTest()
}
<commit_msg>Not incrementing the tick on test end<commit_after>var Suite = require('./Suite')
  , Test = require('./Test')
  , EventEmitter = require('events').EventEmitter
  , util = require('util')
  , path = require('path')
  , Date = global.Date

/**
 * Creates a new PPUnit object
 *
 * @constructor
 */
var PPUnit = function (options) {
    var self = this

    PPUnit.super_.call(self)

    options = options || {}
    self.concurrency = options.concurrency || -1

    self.rootSuite = new Suite(undefined)
    self.rootSuite.timeout(2000)
    self.rootSuite.globallyExclusive()
    self.rootSuite.locallyExclusiveTests()

    self.allTests = []
    self.failures = []
    self.tickId = 0

    self.stats = {
        suites: 0
      , tests: 0
      , skipped: 0
      , passes: 0
      , failures: 0
      , completed: 0
      , startTime: 0
      , maxConcurrency: 0
      , currentlyRunning: 0
      , end: undefined
      , duration: undefined
    }

    self._queue = []
    self._nextId = 1
    self._files = []
    self._bailing = false

    process.on('SIGINT', function () {
        self._bail()
    })
}

util.inherits(PPUnit, EventEmitter)
module.exports = PPUnit

/**
 * Adds a file that contains tests to be run
 *
 * @param {String} file Path to the file
 */
PPUnit.prototype.addFile = function (file) {
    this._files.push(path.resolve(file))
}

/**
 * Runs the test suites
 *
 * @param {function} callback A function to call after finish is emitted
 */
PPUnit.prototype.run = function (callback) {
    this._loadFiles()

    var self = this

    self.rootSuite.on('test', function (test) {
        self._addTest(test)
    })

    self.rootSuite.on('suite', function (suite) {
        suite.id = self._nextId++
    })

    self.rootSuite.prepare()

    self.stats.startTime = new Date
    self.emit('start')

    self.allTests[self.allTests.length - 1].on('finish', function () {
        self.stats.end = new Date
        self.stats.duration = new Date - self.stats.startTime

        self.emit('finish')
        callback()
    })

    self._queue.push(self.allTests[0])
    self._nextTest()
}

/**
 * Loads/requires the files and builds the test suites
 *
 * @private
 */
PPUnit.prototype._loadFiles = function () {
    var self = this

    self._files.forEach(function (file) {
        //TODO: Emit pre-require and require
        require(file)
    })
}

/**
 * Adds a test to the list and wires up events
 *
 * @param {Test} newTest The test to add
 */
PPUnit.prototype._addTest = function (newTest) {
    var self = this

    newTest.id = this._nextId++
    if (newTest.type !== Test.TYPE.ROOT) {
        self.stats.tests++
    }

    newTest.on('ready', function () {
        if (self._bailing) {
            return
        }

        self._queue.push(newTest)
        self._nextTest()
    })

    newTest.on('start', function () {
        self.emit('test start', newTest)
    })

    newTest.on('finish', function (previous) {
        if (!previous) {
            newTest.tickEnd = self.tickId
            self.stats.currentlyRunning--
        }

        if (newTest.type !== Test.TYPE.ROOT) {
            if (!newTest.completedNumber) {
                newTest.completedNumber = ++self.stats.completed
            }

            switch (newTest.result) {
                case Test.RESULT.SUCCESS:
                    self.stats.passes++
                    break

                case Test.RESULT.HOOK_FAILURE:
                case Test.RESULT.TIMEOUT:
                case Test.RESULT.FAILURE:
                    if (previous && previous.result === Test.RESULT.SUCCESS) {
                        self.stats.passes--
                    }

                    if (!previous || previous.result === Test.RESULT.SUCCESS) {
                        self.failures.push(newTest)
                        self.stats.failures++
                        newTest.failureNumber = self.stats.failures
                    }

                    break

                case Test.RESULT.SKIPPED:
                    self.stats.skipped++
                    break
            }
        }

        self.emit('test finish', newTest, previous)
        self._nextTest()
    })

    if (newTest.exclusivity === Test.EXCLUSIVITY.GLOBAL) {
        var edges = []

        this.allTests.forEach(function (test) {
            if (test.nextTests.length) {
                return
            }

            edges.push(test)
        })

        newTest.addPriorTests(edges)
    }

    this.allTests.push(newTest)
}

/**
 * Attempts to run the next ready test
 * Depending on the concurrency limit, many tests may be running at the same time
 *
 * @private
 */
PPUnit.prototype._nextTest = function () {
    var self = this
    process.nextTick(function () {
        if (self._queue.length > 0 && (self.concurrency < 1 || self.stats.currentlyRunning < self.concurrency)) {
            var test = self._queue.shift()
            test.tickStart = self.tickId++
            self.stats.currentlyRunning++
            self.stats.maxConcurrency = Math.max(self.stats.maxConcurrency, self.stats.currentlyRunning)

            test.run()

            self._nextTest()
        }
    })
}

/**
 * Stops the run and marks remaining tests as skipped
 *
 * @private
 */
PPUnit.prototype._bail = function () {
    var self = this
    self._bailing = true
    self._queue = []

    self.allTests.forEach(function (test, index) {
        if (test.state === Test.STATE.COMPLETED || index === (self.allTests.length - 1)) {
            return
        }

        if (test.type !== Test.TYPE.ROOT) {
            test.complete(void 0, Test.RESULT.SKIPPED)
        } else {
            test.complete(void 0, Test.RESULT.SUCCESS)
        }
    })

    self._queue.push(self.allTests[self.allTests.length - 1])
    self._nextTest()
}
<|endoftext|>


<commit_before>const { Boards }    = require('boards');
const fileExists    = require('file-exists');
const procurator    = require('procurator');
const { Homefront } = require('homefront');
const path          = require('path');
const glob          = require('glob');

class Runner {
  constructor(config) {
    this.config = Homefront.merge({ tasks: {}, appRoot: '.', templateRoot: '.' }, config);
    this.boards = new Boards({ discoveryConfig: { prefix: 'boards-preset' } });
  }

  composeTask(task, parameters) {
    if (this.config.tasks[task]) {
      parameters._tasks = this.config.tasks;

      return this.config.tasks[task];
    }

    // Preset. Check if exists.
    const parts      = task.split(':');
    const presetName = parts.shift();
    const presets    = this.getPresets();
    const preset     = presets[presetName];
    task             = parts[0];

    if (!preset) {
      throw new Error(`Preset "${presetName}" not found.`);
    }

    parameters.fallbackSourceDirectory = preset.templateRoot;
    parameters._tasks                  = preset.tasks;

    return preset.tasks[task];
  }

  getPresets() {
    if (!this.presets) {
      this.presets         = this.boards.getPlugins();
      this.presets.default = require('boards-preset-default');
    }

    return this.presets;
  }

  run(task, parameters) {
    parameters = Homefront.merge({}, this.config.parameters || {}, parameters);

    return this.apply('default:prepare', parameters).then(() => this.apply(task, parameters));
  }

  apply(task, parameters) {
    let instructions = task;

    if (typeof task === 'string') {
      instructions = this.composeTask(task, parameters);

      if (!instructions) {
        return Promise.reject(new Error(`Instructions for task "${task}" not found.`));
      }
    }

    if (!instructions) {
      return Promise.reject(new Error(`Invalid instructions provided.`));
    }

    if (!Array.isArray(instructions)) {
      instructions = [instructions];
    }

    let previousTask = null;

    return Promise.all(instructions.map(instruction => {
      let runner;

      if (previousTask) {
        runner       = previousTask.then(() => this.runTask(instruction, parameters));
        previousTask = null;
      } else {
        runner = this.runTask(instruction, parameters);
      }

      if (instruction.sync) {
        previousTask = runner;
      }

      return runner;
    }));
  }

  prepareParams(method, params) {
    const preparedParams = method(params);

    if (typeof preparedParams === 'object') {
      return preparedParams;
    }

    return params;
  }

  runTask(instruction, parameters) {
    instruction.from = instruction.from || '';

    // Prepare for step. Copy parameters to not affect other tasks.
    if (typeof instruction.prepare === 'function') {
      parameters = this.prepareParams(instruction.prepare, Homefront.merge({}, parameters));
    }

    // Allow dynamic tasks to be supplied.
    if (typeof instruction.dynamicTask === 'function') {
      return Promise.resolve(instruction.dynamicTask(parameters)).then(tasks => {
        this.apply(tasks, parameters);
      });
    }

    if (typeof instruction.definedTask !== 'undefined') {
      if (typeof instruction.definedTask !== 'string') {
        throw new Error(`definedTask must be a string. Got ${typeof instruction.definedTask}.`);
      }

      if (instruction.isolated && typeof instruction.prepare !== 'function') {
        parameters = Homefront.merge({}, parameters);
      }

      return this.apply(instruction.definedTask, parameters);
    }

    if (typeof instruction.task === 'function') {
      return instruction.task(parameters, this.boards);
    }

    if (typeof this[instruction.task] !== 'function') {
      throw new Error(`Invalid task "${instruction.task}" supplied`);
    }

    return this[instruction.task](instruction, parameters);
  }

  modify(instruction, parameters) {
    return this.boards.generate('ModificationGenerator', Object.assign({}, parameters, {
      sourceDirectory: this.config.appRoot,
      targetDirectory: this.config.appRoot,
      sourceFile     : this.getTarget(instruction.target, parameters),
      modify         : { patch: instruction.patch }
    }));
  }

  applyGenerate(template, target, sourceDirectory, instruction, parameters) {
    const parsed = path.parse(this.getTarget(target, parameters));

    return this.boards.generate('TemplateGenerator', Object.assign({}, parameters, {
      targetFile     : parsed.base,
      targetDirectory: path.join(this.config.appRoot, parsed.dir || '.'),
      sourceFile     : this.getTarget(template, parameters),
      sourceDirectory
    }));
  }

  generate(instruction, parameters) {
    if (!instruction.glob) {
      const template = this.getTarget(instruction.template, parameters);

      return this.applyGenerate(template, instruction.target, this.getTemplateDirectory(instruction, parameters), instruction, parameters);
    }

    const glob         = this.getTarget(instruction.glob, parameters);
    const globPromises = [];

    if (this.config.templateRoot) {
      globPromises.push(this.glob(glob, path.join(this.config.templateRoot, instruction.from)));
    } else {
      // Push empty array so we can use array position further down
      globPromises.push(Promise.resolve([]));
    }

    if (parameters.fallbackSourceDirectory) {
      globPromises.push(this.glob(glob, path.join(parameters.fallbackSourceDirectory, instruction.from)));
    }

    return Promise.all(globPromises)
      .then(globbed => {
        const projectMatches = globbed[0];
        const generates      = [];
        const makeApply      = (match, dir) => {
          const target = path.join(instruction.target, match);

          generates.push(this.applyGenerate(match, target, path.join(dir, instruction.from), instruction, parameters));
        };

        projectMatches.forEach(match => makeApply(match, this.config.templateRoot));

        if (globbed[1]) {
          globbed[1]
            .filter(match => !projectMatches.includes(match))
            .forEach(match => makeApply(match, parameters.fallbackSourceDirectory));
        }

        return Promise.all(generates);
      });
  }

  getTemplateDirectory(instruction, parameters) {
    if (fileExists.sync(path.resolve(this.config.templateRoot, instruction.template))) {
      return this.config.templateRoot;
    }

    const fallback = parameters.fallbackSourceDirectory;

    if (!fallback) {
      throw new Error(`Template "${instruction.template}" not found.`);
    }

    if (!fileExists.sync(path.resolve(fallback, instruction.template))) {
      throw new Error(`Preset template "${instruction.template}" not found.`);
    }

    return fallback;
  }

  glob(pattern, cwd) {
    return new Promise((resolve, reject) => {
      glob(pattern, { nodir: true, cwd }, (error, results) => {
        if (error) {
          return reject(error);
        }

        return resolve(results);
      });
    });
  }

  getTarget(target, parameters) {
    if (typeof target === 'function') {
      return target(parameters);
    }

    return procurator.sync(target, parameters);
  }
}

module.exports.Runner = Runner;
<commit_msg>feat(Runner): add default tasks task<commit_after>const { Boards }    = require('boards');
const fileExists    = require('file-exists');
const procurator    = require('procurator');
const { Homefront } = require('homefront');
const path          = require('path');
const glob          = require('glob');

class Runner {
  constructor(config) {
    this.config = Homefront.merge({ tasks: {}, appRoot: '.', templateRoot: '.' }, config);
    this.boards = new Boards({ discoveryConfig: { prefix: 'boards-preset' } });
  }

  composeTask(task, parameters) {
    if (this.config.tasks[task]) {
      parameters._tasks = this.config.tasks;

      return this.config.tasks[task];
    }

    // Preset. Check if exists.
    const parts      = task.split(':');
    const presetName = parts.shift();
    const presets    = this.getPresets();
    const preset     = presets[presetName];
    task             = parts[0];

    if (!preset) {
      throw new Error(`Preset "${presetName}" not found.`);
    }

    parameters.fallbackSourceDirectory = preset.templateRoot;
    parameters._tasks                  = preset.tasks;

    if (!preset.tasks[task] && task === 'tasks') {
      return presets.default.tasks.tasks;
    }

    return preset.tasks[task];
  }

  getPresets() {
    if (!this.presets) {
      this.presets         = this.boards.getPlugins();
      this.presets.default = require('boards-preset-default');
    }

    return this.presets;
  }

  run(task, parameters) {
    parameters = Homefront.merge({}, this.config.parameters || {}, parameters);

    return this.apply('default:prepare', parameters).then(() => this.apply(task, parameters));
  }

  apply(task, parameters) {
    let instructions = task;

    if (typeof task === 'string') {
      instructions = this.composeTask(task, parameters);

      if (!instructions) {
        return Promise.reject(new Error(`Instructions for task "${task}" not found.`));
      }
    }

    if (!instructions) {
      return Promise.reject(new Error(`Invalid instructions provided.`));
    }

    if (!Array.isArray(instructions)) {
      instructions = [instructions];
    }

    let previousTask = null;

    return Promise.all(instructions.map(instruction => {
      let runner;

      if (previousTask) {
        runner       = previousTask.then(() => this.runTask(instruction, parameters));
        previousTask = null;
      } else {
        runner = this.runTask(instruction, parameters);
      }

      if (instruction.sync) {
        previousTask = runner;
      }

      return runner;
    }));
  }

  prepareParams(method, params) {
    const preparedParams = method(params);

    if (typeof preparedParams === 'object') {
      return preparedParams;
    }

    return params;
  }

  runTask(instruction, parameters) {
    instruction.from = instruction.from || '';

    // Prepare for step. Copy parameters to not affect other tasks.
    if (typeof instruction.prepare === 'function') {
      parameters = this.prepareParams(instruction.prepare, Homefront.merge({}, parameters));
    }

    // Allow dynamic tasks to be supplied.
    if (typeof instruction.dynamicTask === 'function') {
      return Promise.resolve(instruction.dynamicTask(parameters)).then(tasks => {
        this.apply(tasks, parameters);
      });
    }

    if (typeof instruction.definedTask !== 'undefined') {
      if (typeof instruction.definedTask !== 'string') {
        throw new Error(`definedTask must be a string. Got ${typeof instruction.definedTask}.`);
      }

      if (instruction.isolated && typeof instruction.prepare !== 'function') {
        parameters = Homefront.merge({}, parameters);
      }

      return this.apply(instruction.definedTask, parameters);
    }

    if (typeof instruction.task === 'function') {
      return instruction.task(parameters, this.boards);
    }

    if (typeof this[instruction.task] !== 'function') {
      throw new Error(`Invalid task "${instruction.task}" supplied`);
    }

    return this[instruction.task](instruction, parameters);
  }

  modify(instruction, parameters) {
    return this.boards.generate('ModificationGenerator', Object.assign({}, parameters, {
      sourceDirectory: this.config.appRoot,
      targetDirectory: this.config.appRoot,
      sourceFile     : this.getTarget(instruction.target, parameters),
      modify         : { patch: instruction.patch }
    }));
  }

  applyGenerate(template, target, sourceDirectory, instruction, parameters) {
    const parsed = path.parse(this.getTarget(target, parameters));

    return this.boards.generate('TemplateGenerator', Object.assign({}, parameters, {
      targetFile     : parsed.base,
      targetDirectory: path.join(this.config.appRoot, parsed.dir || '.'),
      sourceFile     : this.getTarget(template, parameters),
      sourceDirectory
    }));
  }

  generate(instruction, parameters) {
    if (!instruction.glob) {
      const template = this.getTarget(instruction.template, parameters);

      return this.applyGenerate(template, instruction.target, this.getTemplateDirectory(instruction, parameters), instruction, parameters);
    }

    const glob         = this.getTarget(instruction.glob, parameters);
    const globPromises = [];

    if (this.config.templateRoot) {
      globPromises.push(this.glob(glob, path.join(this.config.templateRoot, instruction.from)));
    } else {
      // Push empty array so we can use array position further down
      globPromises.push(Promise.resolve([]));
    }

    if (parameters.fallbackSourceDirectory) {
      globPromises.push(this.glob(glob, path.join(parameters.fallbackSourceDirectory, instruction.from)));
    }

    return Promise.all(globPromises)
      .then(globbed => {
        const projectMatches = globbed[0];
        const generates      = [];
        const makeApply      = (match, dir) => {
          const target = path.join(instruction.target, match);

          generates.push(this.applyGenerate(match, target, path.join(dir, instruction.from), instruction, parameters));
        };

        projectMatches.forEach(match => makeApply(match, this.config.templateRoot));

        if (globbed[1]) {
          globbed[1]
            .filter(match => !projectMatches.includes(match))
            .forEach(match => makeApply(match, parameters.fallbackSourceDirectory));
        }

        return Promise.all(generates);
      });
  }

  getTemplateDirectory(instruction, parameters) {
    if (fileExists.sync(path.resolve(this.config.templateRoot, instruction.template))) {
      return this.config.templateRoot;
    }

    const fallback = parameters.fallbackSourceDirectory;

    if (!fallback) {
      throw new Error(`Template "${instruction.template}" not found.`);
    }

    if (!fileExists.sync(path.resolve(fallback, instruction.template))) {
      throw new Error(`Preset template "${instruction.template}" not found.`);
    }

    return fallback;
  }

  glob(pattern, cwd) {
    return new Promise((resolve, reject) => {
      glob(pattern, { nodir: true, cwd }, (error, results) => {
        if (error) {
          return reject(error);
        }

        return resolve(results);
      });
    });
  }

  getTarget(target, parameters) {
    if (typeof target === 'function') {
      return target(parameters);
    }

    return procurator.sync(target, parameters);
  }
}

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


<commit_before>'use strict';

var _ = require('lodash');

module.exports = function calcDelta (oldData, newData) {

  var delta = {'delta': true};
  var changesFound = false;

  // if there's no updates done so far, just return the full set
  if (!oldData.sgvs) { return newData; }

  function nsArrayTreatments(oldArray, newArray) {
    var result = [];

    // check for add, change
    var l = newArray.length;
    var m = oldArray.length;
    var found, founddiff, no, oo, i, j;
    for (i = 0; i < l; i++) {
      no = newArray[i];
      found = false;
      founddiff = false;
      for (j = 0; j < m; j++) {
        oo = oldArray[j];
        no._id = no._id.toString();
        if (no._id === oo._id) {
          found = true;
          var oo_copy = _.clone(oo);
          var no_copy = _.clone(no);
          delete oo_copy.mgdl;
          delete no_copy.mgdl;
          if (!_.isEqual(oo_copy, no_copy)) {
            founddiff = true;
          }
          break;
        }
      }
      if (founddiff) {
        var nno = _.clone(no);
        nno.action = 'update';
        result.push(nno);
      }
      if (!found) {
        result.push(no);
      }
    }

    //check for delete
    for (j = 0; j < m; j++) {
      oo = oldArray[j];
      found = false;
      for (i = 0; i < l; i++) {
        no = newArray[i];
        if (no._id === oo._id) {
          found = true;
          break;
        }
      }
      if (!found) {
        result.push({ _id: oo._id, action: 'remove' });
      }
    }

    return result;
  }

  function nsArrayDiff(oldArray, newArray) {
    var seen = {};
    var l = oldArray.length;
    for (var i = 0; i < l; i++) {
      seen[oldArray[i].mills] = true;
    }
    var result = [];
    l = newArray.length;
    for (var j = 0; j < l; j++) {
      if (!seen.hasOwnProperty(newArray[j].mills)) {
        result.push(newArray[j]);
      }
    }
    return result;
  }

  function sort(values) {
    values.sort(function sorter(a, b) {
      return a.mills - b.mills;
    });
  }

  function compressArrays(delta, newData) {
    // array compression
    var compressibleArrays = ['sgvs', 'treatments', 'mbgs', 'cals', 'devicestatus'];
    var changesFound = false;

    for (var array in compressibleArrays) {
      if (compressibleArrays.hasOwnProperty(array)) {
        var a = compressibleArrays[array];
        if (newData.hasOwnProperty(a)) {

          // if previous data doesn't have the property (first time delta?), just assign data over
          if (!oldData.hasOwnProperty(a)) {
            delta[a] = newData[a];
            changesFound = true;
            continue;
          }

          // Calculate delta and assign delta over if changes were found
          var deltaData = (a === 'treatments' ? nsArrayTreatments(oldData[a], newData[a]) : nsArrayDiff(oldData[a], newData[a]));
          if (deltaData.length > 0) {
            console.log('delta changes found on', a);
            changesFound = true;
            sort(deltaData);
            delta[a] = deltaData;
          }
        }
      }
    }
    return {'delta': delta, 'changesFound': changesFound};
  }

  function deleteSkippables(delta,newData) {
    // objects
    var skippableObjects = ['profiles'];
    var changesFound = false;

    for (var object in skippableObjects) {
      if (skippableObjects.hasOwnProperty(object)) {
        var o = skippableObjects[object];
        if (newData.hasOwnProperty(o)) {
          if (JSON.stringify(newData[o]) !== JSON.stringify(oldData[o])) {
            console.log('delta changes found on', o);
            changesFound = true;
            delta[o] = newData[o];
          }
        }
      }
    }
    return {'delta': delta, 'changesFound': changesFound};
  }

  delta.lastUpdated = newData.lastUpdated;

  var compressedDelta = compressArrays(delta, newData);
  delta = compressedDelta.delta;
  if (compressedDelta.changesFound) { changesFound = true; }

  var skippedDelta = deleteSkippables(delta, newData);
  delta = skippedDelta.delta;
  if (skippedDelta.changesFound) { changesFound = true; }

  if (changesFound) { return delta; }
  return newData;

};
<commit_msg>Fix first delta (was comparing a string to Mongo object ID using === a couple lines down), causing the first delta update send all treatments twice, instead of 0 treatments.<commit_after>'use strict';

var _ = require('lodash');

module.exports = function calcDelta (oldData, newData) {

  var delta = {'delta': true};
  var changesFound = false;

  // if there's no updates done so far, just return the full set
  if (!oldData.sgvs) { return newData; }

  function nsArrayTreatments(oldArray, newArray) {
    var result = [];

    // check for add, change
    var l = newArray.length;
    var m = oldArray.length;
    var found, founddiff, no, oo, i, j;
    for (i = 0; i < l; i++) {
      no = newArray[i];
      no._id = no._id.toString();
      found = false;
      founddiff = false;
      for (j = 0; j < m; j++) {
        oo = oldArray[j];
        oo._id = oo._id.toString();
        if (no._id === oo._id) {
          found = true;
          var oo_copy = _.clone(oo);
          var no_copy = _.clone(no);
          delete oo_copy.mgdl;
          delete no_copy.mgdl;
          if (!_.isEqual(oo_copy, no_copy)) {
            founddiff = true;
          }
          break;
        }
      }
      if (founddiff) {
        var nno = _.clone(no);
        nno.action = 'update';
        result.push(nno);
      }
      if (!found) {
        result.push(no);
      }
    }

    //check for delete
    for (j = 0; j < m; j++) {
      oo = oldArray[j];
      found = false;
      for (i = 0; i < l; i++) {
        no = newArray[i];
        if (no._id === oo._id) {
          found = true;
          break;
        }
      }
      if (!found) {
        result.push({ _id: oo._id, action: 'remove' });
      }
    }

    return result;
  }

  function nsArrayDiff(oldArray, newArray) {
    var seen = {};
    var l = oldArray.length;
    for (var i = 0; i < l; i++) {
      seen[oldArray[i].mills] = true;
    }
    var result = [];
    l = newArray.length;
    for (var j = 0; j < l; j++) {
      if (!seen.hasOwnProperty(newArray[j].mills)) {
        result.push(newArray[j]);
      }
    }
    return result;
  }

  function sort(values) {
    values.sort(function sorter(a, b) {
      return a.mills - b.mills;
    });
  }

  function compressArrays(delta, newData) {
    // array compression
    var compressibleArrays = ['sgvs', 'treatments', 'mbgs', 'cals', 'devicestatus'];
    var changesFound = false;

    for (var array in compressibleArrays) {
      if (compressibleArrays.hasOwnProperty(array)) {
        var a = compressibleArrays[array];
        if (newData.hasOwnProperty(a)) {

          // if previous data doesn't have the property (first time delta?), just assign data over
          if (!oldData.hasOwnProperty(a)) {
            delta[a] = newData[a];
            changesFound = true;
            continue;
          }

          // Calculate delta and assign delta over if changes were found
          var deltaData = (a === 'treatments' ? nsArrayTreatments(oldData[a], newData[a]) : nsArrayDiff(oldData[a], newData[a]));
          if (deltaData.length > 0) {
            console.log('delta changes found on', a);
            changesFound = true;
            sort(deltaData);
            delta[a] = deltaData;
          }
        }
      }
    }
    return {'delta': delta, 'changesFound': changesFound};
  }

  function deleteSkippables(delta,newData) {
    // objects
    var skippableObjects = ['profiles'];
    var changesFound = false;

    for (var object in skippableObjects) {
      if (skippableObjects.hasOwnProperty(object)) {
        var o = skippableObjects[object];
        if (newData.hasOwnProperty(o)) {
          if (JSON.stringify(newData[o]) !== JSON.stringify(oldData[o])) {
            console.log('delta changes found on', o);
            changesFound = true;
            delta[o] = newData[o];
          }
        }
      }
    }
    return {'delta': delta, 'changesFound': changesFound};
  }

  delta.lastUpdated = newData.lastUpdated;

  var compressedDelta = compressArrays(delta, newData);
  delta = compressedDelta.delta;
  if (compressedDelta.changesFound) { changesFound = true; }

  var skippedDelta = deleteSkippables(delta, newData);
  delta = skippedDelta.delta;
  if (skippedDelta.changesFound) { changesFound = true; }

  if (changesFound) { return delta; }
  return newData;

};
<|endoftext|>