<commit_before>/**
 * KISSY Module Compiler
 * @author: daxingplay<daxingplay@gmail.com>
 * @time: 13-3-12 11:41
 * @description:
 */

var fs = require('fs'),
    path = require('path'),
    colors = require('colors'),
    _ = require('lodash'),
    iconv = require('iconv-lite'),
    Compiler = require('./lib/compiler'),
    utils = require('./lib/utils'),
    parseConfig = require('./lib/parse-config');

function getModulePath(moduleName, config){
    for(var i = 0; i < config.packages.length; i++){
        var pkg = config.packages[i],
            mod = moduleName.match(new RegExp(pkg.name + '\/(.*)'));
        if(mod && mod[1]){
            var modulePath = path.resolve(pkg.path, pkg.name, mod[1].replace(/\.js/, '') + '.js');
            if(fs.existsSync(modulePath)){
                return modulePath;
            }
        }
    }
    return false;
}

module.exports = {
    _config: {},
    config: function(cfg){
        var self = this;
        if(cfg){
            self._config = parseConfig.parse(cfg, self._config);
        }
        self._config.packages = [];
        for(var pkg in self._config.pkgs){
            self._config.packages.push(self._config.pkgs[pkg]);
        }
        return this._config;
    },
    analyze: function(inputFile){
        var self = this;
        // to make sure there is at least one package in config.
        self._config = parseConfig.check(self._config, inputFile);
        // start to analyze.
        var c = new Compiler(self._config);
        return c.analyze(inputFile);
    },
    build: function(inputFilePath, outputFilePath, outputCharset, depFile, traverse){
        var self = this,
            targets = [],
            result = {
                'success': true,
                'files': []
            },
            combo = [];
        // for object arguments.
        if(_.isPlainObject(inputFilePath) && inputFilePath.src){
            outputFilePath = inputFilePath.dest;
            outputCharset = inputFilePath.outputCharset;
            depFile = inputFilePath.depPath;
            traverse = inputFilePath.traverse;
            inputFilePath = inputFilePath.src;
        }

        if(_.isString(inputFilePath)){
            var target = path.resolve(inputFilePath);
            if(fs.existsSync(target)){
                if(fs.statSync(target).isDirectory()){
//                    var files = fs.readdirSync(target);
                    _.forEach(utils.traverseDirSync(target, traverse), function(file){
                        var inputFile = path.resolve(target, file),
                            outputFile = path.resolve(outputFilePath, path.relative(target, file));
                        if(path.extname(inputFile) === '.js'){
                            targets.push({
                                src: inputFile,
                                dest: outputFile
                            });
                        }
                    });
                }else{
                    targets.push({
                        src: target,
                        dest: outputFilePath
                    });
                }
            }else{
                // MC.build('pkgName/abc');
                // in this case, package must be configured.
                var modulePath = getModulePath(inputFilePath, self._config);
                if(modulePath){
                    targets.push({
                        src: modulePath,
                        dest: outputFilePath
                    });
                }else{
                    console.error('[err]'.bold.green+' cannot find input file %s ', inputFilePath);
                }
            }
        }else if(_.isPlainObject(inputFilePath)){
            _.forEach(inputFilePath, function(file){
                if(fs.src){
                    targets.push({
                        src: file.src,
                        dest: file.dest ? file.dest : path.dirname(file.src)
                    });
                }
            });
        }else if(_.isArray(inputFilePath)){
            var destIsArray = _.isArray(outputFilePath) ? outputFilePath : false;
            _.forEach(inputFilePath, function(file, index){
                targets.push({
                    src: file,
                    dest: destIsArray && outputFilePath[index] ? outputFilePath[index] : outputFilePath
                });
            });
        }

        _.forEach(targets, function(file, index){
            self._config = parseConfig.check(self._config, file.src);
            var config = _.cloneDeep(self._config);
            var kmc = new Compiler(config);
            var re = kmc.build(file.src, file.dest, outputCharset);
            re.modules = kmc.modules;
            depFile && combo.push(re.autoCombo);
            result.files.push(re);
        });
        result.success = result.files.length !== 0;

        if(depFile){
            utils.writeFileSync(path.resolve(path.dirname(outputFilePath), depFile),
                utils.joinCombo(combo,path.extname(depFile)==='.json'), outputCharset);
        }

        return result;
    },
    combo: function(inputFile, depFileName, depFileCharset, fixModuleName, returnDependencies, outputDir,comboOnly){
        var self = this,
            content,
            config;
        if(_.isObject(inputFile)){
            depFileName = inputFile.depPath;
            depFileCharset = inputFile.depCharset;
            fixModuleName = inputFile.fixModuleName;
            returnDependencies = inputFile.showFullResult;
            outputDir = inputFile.dest;
            inputFile = inputFile.src;
        }
        self._config = parseConfig.check(self._config, inputFile);
        config = _.cloneDeep(self._config);
        fixModuleName = fixModuleName !== false;
		var outputFile = outputDir ? path.resolve(outputDir,path.basename(inputFile)) : '';
        var c = new Compiler(config,outputFile);
        var result = c.analyze(inputFile);
        content = c.combo(fixModuleName, outputDir,comboOnly,path.extname(depFileName)==='.json');
        if(content && depFileName){
            utils.writeFileSync(depFileName, content, depFileCharset);
        }
        return returnDependencies === true ? { files: [result], success: true, modules: c.modules, content: content } : content;
    },
    clean: function(){
        this._config = {
            packages: [],
            exclude: [],
            charset: 'utf8',
            silent: false
        };
        return true;
    }
};
<commit_msg>add comboOnly to options obj<commit_after>/**
 * KISSY Module Compiler
 * @author: daxingplay<daxingplay@gmail.com>
 * @time: 13-3-12 11:41
 * @description:
 */

var fs = require('fs'),
    path = require('path'),
    colors = require('colors'),
    _ = require('lodash'),
    iconv = require('iconv-lite'),
    Compiler = require('./lib/compiler'),
    utils = require('./lib/utils'),
    parseConfig = require('./lib/parse-config');

function getModulePath(moduleName, config){
    for(var i = 0; i < config.packages.length; i++){
        var pkg = config.packages[i],
            mod = moduleName.match(new RegExp(pkg.name + '\/(.*)'));
        if(mod && mod[1]){
            var modulePath = path.resolve(pkg.path, pkg.name, mod[1].replace(/\.js/, '') + '.js');
            if(fs.existsSync(modulePath)){
                return modulePath;
            }
        }
    }
    return false;
}

module.exports = {
    _config: {},
    config: function(cfg){
        var self = this;
        if(cfg){
            self._config = parseConfig.parse(cfg, self._config);
        }
        self._config.packages = [];
        for(var pkg in self._config.pkgs){
            self._config.packages.push(self._config.pkgs[pkg]);
        }
        return this._config;
    },
    analyze: function(inputFile){
        var self = this;
        // to make sure there is at least one package in config.
        self._config = parseConfig.check(self._config, inputFile);
        // start to analyze.
        var c = new Compiler(self._config);
        return c.analyze(inputFile);
    },
    build: function(inputFilePath, outputFilePath, outputCharset, depFile, traverse){
        var self = this,
            targets = [],
            result = {
                'success': true,
                'files': []
            },
            combo = [];
        // for object arguments.
        if(_.isPlainObject(inputFilePath) && inputFilePath.src){
            outputFilePath = inputFilePath.dest;
            outputCharset = inputFilePath.outputCharset;
            depFile = inputFilePath.depPath;
            traverse = inputFilePath.traverse;
            inputFilePath = inputFilePath.src;
        }

        if(_.isString(inputFilePath)){
            var target = path.resolve(inputFilePath);
            if(fs.existsSync(target)){
                if(fs.statSync(target).isDirectory()){
//                    var files = fs.readdirSync(target);
                    _.forEach(utils.traverseDirSync(target, traverse), function(file){
                        var inputFile = path.resolve(target, file),
                            outputFile = path.resolve(outputFilePath, path.relative(target, file));
                        if(path.extname(inputFile) === '.js'){
                            targets.push({
                                src: inputFile,
                                dest: outputFile
                            });
                        }
                    });
                }else{
                    targets.push({
                        src: target,
                        dest: outputFilePath
                    });
                }
            }else{
                // MC.build('pkgName/abc');
                // in this case, package must be configured.
                var modulePath = getModulePath(inputFilePath, self._config);
                if(modulePath){
                    targets.push({
                        src: modulePath,
                        dest: outputFilePath
                    });
                }else{
                    console.error('[err]'.bold.green+' cannot find input file %s ', inputFilePath);
                }
            }
        }else if(_.isPlainObject(inputFilePath)){
            _.forEach(inputFilePath, function(file){
                if(fs.src){
                    targets.push({
                        src: file.src,
                        dest: file.dest ? file.dest : path.dirname(file.src)
                    });
                }
            });
        }else if(_.isArray(inputFilePath)){
            var destIsArray = _.isArray(outputFilePath) ? outputFilePath : false;
            _.forEach(inputFilePath, function(file, index){
                targets.push({
                    src: file,
                    dest: destIsArray && outputFilePath[index] ? outputFilePath[index] : outputFilePath
                });
            });
        }

        _.forEach(targets, function(file, index){
            self._config = parseConfig.check(self._config, file.src);
            var config = _.cloneDeep(self._config);
            var kmc = new Compiler(config);
            var re = kmc.build(file.src, file.dest, outputCharset);
            re.modules = kmc.modules;
            depFile && combo.push(re.autoCombo);
            result.files.push(re);
        });
        result.success = result.files.length !== 0;

        if(depFile){
            utils.writeFileSync(path.resolve(path.dirname(outputFilePath), depFile),
                utils.joinCombo(combo,path.extname(depFile)==='.json'), outputCharset);
        }

        return result;
    },
    combo: function(inputFile, depFileName, depFileCharset, fixModuleName, returnDependencies, outputDir,comboOnly){
        var self = this,
            content,
            config;
        if(_.isObject(inputFile)){
            depFileName = inputFile.depPath;
            depFileCharset = inputFile.depCharset;
            fixModuleName = inputFile.fixModuleName;
            returnDependencies = inputFile.showFullResult;
            outputDir = inputFile.dest;
            inputFile = inputFile.src;
            comboOnly = inputFile.comboOnly;
        }
        self._config = parseConfig.check(self._config, inputFile);
        config = _.cloneDeep(self._config);
        fixModuleName = fixModuleName !== false;
		var outputFile = outputDir ? path.resolve(outputDir,path.basename(inputFile)) : '';
        var c = new Compiler(config,outputFile);
        var result = c.analyze(inputFile);
        content = c.combo(fixModuleName, outputDir,comboOnly,path.extname(depFileName)==='.json');
        if(content && depFileName){
            utils.writeFileSync(depFileName, content, depFileCharset);
        }
        return returnDependencies === true ? { files: [result], success: true, modules: c.modules, content: content } : content;
    },
    clean: function(){
        this._config = {
            packages: [],
            exclude: [],
            charset: 'utf8',
            silent: false
        };
        return true;
    }
};
<|endoftext|>


<commit_before>var yargs = require('yargs');
var fs    = require('fs');
var http  = require('http');
var debug = require('debug')('word-counter:index');
var client_parse = require('./lib/client_parse.js');

var argv = yargs
    .option('c', {
      alias: 'client',
      type: 'array'
    })
    .option('s', {
      alias: 'search',
      type: 'string'
    })
    .option('f', {
      alias: 'file',
      type: 'string'
    })
    .argv;

var
  clients = argv.client,
  search = argv.search,
  filename = argv.file,
  fileArray = [],
  countArray = 0,
  ocurrences = 0,
  options = {
    host: 'localhost',
    port: 5050,
    method: 'POST',
    path: '/',
    headers: {
      'Content-Type': 'application/json'
    }
  },
  request = null;

// Lê o arquivo
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  // Separa o arquivo em pedaços e guarda no array `fileArray`
  fileArray = data.match(/([^\s]+\s\s*){1,200}/g);

  mountOptions();
});

// Monta as opções de cada client para enviar
function mountOptions() {
  for (var i = 0; i < clients.length; i++) {
    var client = clients[i];
    // debug(client);
    var options = client_parse(client);
    var postData = getPostData();
    countArray++;

    if (postData) {
      sendRequest(options, postData);
    } else {
      debug("Ultimo pedaco do array ja foi enviado");
    }
  }
};

function getPostData() {
  if(countArray < fileArray.length) {
    return JSON.stringify({
      'content': fileArray[countArray],
      'search': search
    });
  } else {
    return false;
  }
};

// Envia para o cliente um pedaço do texto e a palavra a ser buscada (Start dos requests)
function sendRequest(options, postData) {
  if(countArray <= fileArray.length) {
    var request = http.request(options, process_client);

    request.on('error', function(e) {
      debug('Problema com o request: ' + e.message);
    });

    request.write(postData);

    request.end();
  }
};

function process_client(res) {
  debug('STATUS: ' + res.statusCode);
  debug(res.headers);
  var client = "http://" + res.connection.remoteAddress + ":" + res.connection.remotePort;

  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    var chunk = JSON.parse(chunk);
    debug(chunk);
    var searchReturned = chunk.search;
    var ocurrencesReturned = chunk.ocurrences;

    ocurrences += ocurrencesReturned;

    if(countArray < fileArray.length) {
      var options = client_parse(client);
      var postData = getPostData();
      countArray++;

      if (postData) {
        sendRequest(options, postData);
      } else {
        debug("Ultimo pedaco do array ja foi enviado");
      }
    } else {
      debug(
        "Foram encontradas " +
        ocurrences +
        " ocorrências da palavra " +
        search +
        " no arquivo: " +
        filename
      );
    }
  });

  res.on('end', function() {
    debug('No more data in response.')
  });
};
<commit_msg>Update log messages<commit_after>var yargs = require('yargs');
var fs    = require('fs');
var http  = require('http');
var debug = require('debug')('word-counter:index');
var client_parse = require('./lib/client_parse.js');

var argv = yargs
    .option('c', {
      alias: 'client',
      type: 'array'
    })
    .option('s', {
      alias: 'search',
      type: 'string'
    })
    .option('f', {
      alias: 'file',
      type: 'string'
    })
    .argv;

var
  clients = argv.client,
  search = argv.search,
  filename = argv.file,
  fileArray = [],
  countArray = 0,
  ocurrences = 0,
  options = {
    host: 'localhost',
    port: 5050,
    method: 'POST',
    path: '/',
    headers: {
      'Content-Type': 'application/json'
    }
  },
  request = null;

// Lê o arquivo
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  // Separa o arquivo em pedaços e guarda no array `fileArray`
  fileArray = data.match(/([^\s]+\s\s*){1,200}/g);

  mountOptions();
});

// Monta as opções de cada client para enviar
function mountOptions() {
  for (var i = 0; i < clients.length; i++) {
    var client = clients[i];
    var options = client_parse(client);
    var postData = getPostData();
    countArray++;

    if (postData) {
      sendRequest(options, postData);
    } else {
      debug('End of file reached');
    }
  }
};

function getPostData() {
  if(countArray < fileArray.length) {
    return JSON.stringify({
      'content': fileArray[countArray],
      'search': search
    });
  } else {
    return false;
  }
};

// Envia para o cliente um pedaço do texto e a palavra a ser buscada (Start dos requests)
function sendRequest(options, postData) {
  if(countArray <= fileArray.length) {
    var request = http.request(options, process_client);

    request.on('error', function(e) {
      debug('Error processing request: ' + e.message);
    });

    request.write(postData);

    request.end();
  }
};

function process_client(res) {
  var client = 'http://' + res.connection.remoteAddress + ':' + res.connection.remotePort;

  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    var chunk = JSON.parse(chunk);
    debug('Client "%s" responded with %o', client, chunk);
    var searchReturned = chunk.search;
    var ocurrencesReturned = chunk.ocurrences;

    ocurrences += ocurrencesReturned;

    if(countArray < fileArray.length) {
      var options = client_parse(client);
      var postData = getPostData();
      countArray++;

      if (postData) {
        sendRequest(options, postData);
      } else {
        debug('End of file reached');
      }
    } else {
      debug('Found %d ocurrences of "%s" on file %s.', ocurrences, search, filename);
    }
  });
};
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-cli-helpers'
};
<commit_msg>Loading member.js<commit_after>/* jshint node: true */
'use strict';

module.exports = {
    name: 'ember-cli-helpers',

    included: function (app) {
        this._super.included(app);

        app.import(app.bowerDirectory + '/moment/moment.js');
    }

};
<|endoftext|>


<commit_before>"use strict";

var _ = require('lodash');
var iterate = require('./lib/iterate');

/**
 * Create instance of Schema
 *
 * @constructors
 * @this {Schema}
 * @class Schema
 * @param {string} [name] - register name
 * @return {Schema}
 */
function Schema (name) {
	if (!(this instanceof Schema)) {
		return new Schema(name);
	}

	if (name != null) {
		Schema.register(name, this);
	}

	this.isRequired = true;
}

Schema.prototype = {

	/**
	 * attach this object to schema
	 *
	 * @method
	 * @param {Schema} schema - attach destination object.
	 * @param {String} name - field name for attach.
	 * @throws {TypeError} If schema isn't Schema type
	 * @throws {TypeError} If name empty or isn't String type
	 * @throws {Error} If schema already has the same key name
	 * @return {Schema} @this
	 */
	attachTo: function (schema, name) {
		if (_.isString(schema)) {
			schema = Schema.get(schema);
		}

		if (!(schema instanceof Schema)) {
			throw new TypeError('schema node must be instance of Schema');
		}

		if (!name || !_.isString(name)) {
			throw new TypeError('invalid scheme field name must be non-empty string, "' + name + '" ' + Object.prototype.toString.call(name) + ' given');
		}

		this.name = name;
		this.path = (schema.path || []).concat(name);

		schema._addField(this, name);

		schema = null;

		return this;
	},

	/**
	 * @private
	 * @method
	 * @param {Schema} schema - attach destination object.
	 * @param {String} name - field name for attach.
	 * @throws {Error} If schema already has the same key name
	 * @return {Schema} @this
	 */
	_addField: function (schema, name) {
		if (!this.keys) {
			this.keys = [];
		} else if (_.contains(this.keys, name)) {
			throw new Error('duplicate key "' + name + '" at "/' + (schema.path && schema.path.join('/')) + '"');
		}

		this.hasNested = true;

		this.keys.push(name);

		if (!this.fields) {
			this.fields = [];
		}

		this.fields.push(schema);
		schema = null;

		return this;
	},

	/**
	 * set validate options. can be called several times
	 *
	 * @method
	 * @param {Array|Object|String|Function} validation - validation options.
	 * @return {Schema} @this
	 */
	validate: function (validation) {
		if (validation) {
			if (!this.validations) {
				this.validations = [];
			}

			if (!_.isArray(validation)) {
				this.validations.push(validation);
			} else {
				this.validations = this.validations.concat(validation);
			}
		}

		return this;
	},

	/**
	 * set nested fields builder
	 *
	 * @method
	 * @param {Function|Schema} builderOrSchema - builder function, has two functions in arguments [required, options].
	 * @throws {TypeError} If nested is not a function if specified
	 * @return {Schema} @this
	 */
	object: function (builderOrSchema) {
		if (this.hasNested) {
			throw new Error('object already defined');
		}

		if (builderOrSchema instanceof Schema) {
			return this._similar(builderOrSchema);
		}

		if (!_.isFunction(builderOrSchema)) {
			throw new TypeError('nested builder must be function');
		}

		builderOrSchema.call(this, this.required.bind(this), this.optional.bind(this));

		return this;
	},

	/**
	 * set nested fields builder with type array
	 *
	 * @method
	 * @param {Function|Schema|Boolean} builderOrSchema - builder function, has two functions in arguments [required, options].
	 * @throws {TypeError} If nested is not a function if specified
	 * @return {Schema} @this
	 */
	array: function (builderOrSchema) {
		if (_.isFunction(builderOrSchema) || builderOrSchema instanceof Schema) {
			this.object(builderOrSchema);
		}

		this.isArray = builderOrSchema == null ? true : Boolean(builderOrSchema);

		return this;
	},

	/**
	 * add new nested schema by construct
	 *
	 * @method
	 * @param {String} name - field name.
	 * @return {Schema} @this
	 */
	field: function (name) {
		return new Schema().attachTo(this, name);
	},

	/**
	 * clone this schema
	 *
	 * @method
	 * @return {Schema} new object (clone)
	 */
	clone: function () {
		var clone = new Schema()._similar(this);

		if (this.isArray != null) {
			clone.isArray = this.isArray;
		}

		if (this.isRequired != null) {
			clone.isRequired = this.isRequired;
		}

		return clone;
	},

	/**
	 * clone schema to this schema object
	 *
	 * @private
	 * @method
	 * @return {Schema} new object (clone)
	 */
	_similar: function (schema) {
		var that = this;

		_.each(schema.fields, function (fieldSchema) {
			fieldSchema.clone().attachTo(that, fieldSchema.name);
		});

		if (schema.validations != null) {
			this.validations = _.cloneDeep(schema.validations);
		}

		if (schema.isRequired != null) {
			this.isRequired = schema.isRequired;
		}

		return this;
	},

	/**
	 * verify value. compare schema with some object.
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check.
	 * @param {Object} [options] - validation options, default is plain object.
	 * @param {Function} done - done-callback.
	 */
	verify: function (value, options, done) {
		if (_.isFunction(options)) {
			done = options;
			options = null;
		}

		options || (options = {});

		if (!_.isFunction(done)) {
			throw new Error('schema verify callback must be function, ' + (typeof done) + ' given');
		}

		var that = this;

		var _done = function (err) {
			if (err instanceof Schema.ValidationError) {
				done(null, false, err);
				return;
			}

			if (err) {
				done(err, false, null);
				return;
			}

			done(null, true, null);
		};

		if (value === undefined) {
			if (this.isRequired) {
				_done(new Schema.ValidationError('required', null, this.path, value));
				return;
			}

			_done();
			return;
		}

		var validations = this.validations;
		if (!_.isEmpty(validations)) {
			if (options.validator) {
				validations = options.validator(validations);
			}

			iterate(validations, function (validation, index, done) {
				validation(value, function (err, isValid, validationError) {
					validationError || (validationError = {});

					if (err) {
						done(err);
						return;
					}

					if (!isValid) {
						done(new Schema.ValidationError(validationError.ruleName, validationError.ruleParams, that.path, value));
						return;
					}

					done(null);
				});
			}, function (err) {
				if (err) {
					done(err);
					return;
				}

				that._validationInner(value, options, _done);
			});
			return;
		}

		that._validationInner(value, options, _done);
	},

	/**
	 * verify inner object
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check
	 * @param {Object} options - validation options
	 * @param {Function} done - done-callback
	 */
	_validationInner: function (value, options, done) {
		var that = this;

		if (Boolean(this.isArray) !== _.isArray(value)) {
			done(new Schema.ValidationError('type', this.isArray ? 'array' : 'object', this.path, value));
			return;
		}

		if (this.isArray) {
			iterate(value, function (value, index, done) {
				that._validateFields(value, options, done);
			}, done);

			return;
		}

		that._validateFields(value, options, done);
	},

	/**
	 * verify inner fields
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check
	 * @param {Object} options - validation options
	 * @param {Function} done - done-callback
	 */
	_validateFields: function (value, options, done) {
		if (!this.hasNested) {
			done();
			return;
		}

		if (!_.isObject(value)) {
			done(new Schema.ValidationError('type', 'object', this.path, value));
			return;
		}

		var diff = _.difference(_.keys(value), this.keys);
		if (diff.length) {
			done(new Schema.ValidationError('unexpected_keys', null, this.path, value));
			return;
		}

		iterate(this.fields, function (fieldSchema, index, done) {
			var fieldValue = value[fieldSchema.name];
			fieldSchema.verify(fieldValue, options, function (err, isValid, validationError) {
				err = err || validationError;
				if (err) {
					done(err);
					return;
				}

				if (isValid == null || isValid) {
					done();
					return;
				}

				done(new Schema.ValidationError(null, null, fieldSchema.path, fieldValue));
			});
		}, done);
	},

	/**
	 * add new required nested schema by construct
	 *
	 * @method
	 * @param {String} [name] - field name.
	 * @param {*} [validation] - validation options.
	 * @return {Schema}
	 */
	required: function (name, validation) {
		if (!arguments.length) {
			this.isRequired = true;
			return this;
		}

		return this.field(name).validate(validation);
	},

	/**
	 * add new optional nested schema by construct
	 *
	 * @method
	 * @param {String} [name] - field name.
	 * @param {*} [validation] - validation options.
	 * @return {Schema}
	 */
	optional: function (name, validation) {
		if (!arguments.length) {
			this.isRequired = false;
			return this;
		}

		var schema = this.field(name).validate(validation);
		schema.isRequired = false;
		return schema;
	}
};

var register = {};

/**
 * Schema register
 *
 * @static
 * @param {String} name - name for register.
 * @param {Schema} schema - schema for register
 * @throws {TypeError} If invalid name type
 * @throws {TypeError} If schema name type
 * @throws {ReferenceError} If schema was already registered
 * @return {Schema}
 */
Schema.register = function (name, schema) {
	if (!_.isString(name)) {
		throw new TypeError('invalid name type, must be string');
	}

	if (!(schema instanceof Schema)) {
		throw new TypeError('invalid schema type, must be instance of Schema');
	}

	if (register.hasOwnProperty(name)) {
		throw new ReferenceError('schema "' + name + '" was already registered');
	}

	register[name] = schema;
	return schema;
};

/**
 * get registered schema
 *
 * @static
 * @param {String} name - name for register.
 * @throws {TypeError} If invalid name type
 * @throws {ReferenceError} If schema was not registered before
 * @return {Schema}
 */
Schema.get = function (name) {
	if (!_.isString(name)) {
		throw new TypeError('invalid name type, must be string');
	}

	if (!register.hasOwnProperty(name)) {
		throw new ReferenceError('schema "' + name + '" was not registered');
	}

	return register[name];
};

Schema.errorMessageMap = {};
Schema.errorMessage = function (ruleName, ruleParams, path, value) {
	var map = Schema.errorMessageMap[ruleName];
	return map ? map(ruleName, ruleParams, path, value) : 'invalid value ' + ruleName + ' in ' + path;
};

/**
 * Create instance of Schema.ValidationError. Error object for info about miss value
 *
 * @constructors
 * @this {Schema.ValidationError}
 * @class Schema.ValidationError
 * @param {string} ruleName - rule name, that failed
 * @param {*} ruleParams - params of rule, that failed
 * @param {Array|null} path -  schema path
 * @param {*} value - value, that failed
 * @return {Schema.ValidationError}
 */
Schema.ValidationError = function ValidationError (ruleName, ruleParams, path, value) {
	if (!(this instanceof ValidationError)) {
		return new Schema.ValidationError(ruleName, ruleParams, path, value);
	}

	ruleName || (ruleName = 'unknown');
	path || (path = []);
	value = _.cloneDeep(value);

	var message = Schema.errorMessage(ruleName, ruleParams, path, value);
	Error.call(this, message);
	this.message = message;
	this.type = this.name = 'ValidationError';
	this.value = value;
	this.path = path;
	this.ruleName = ruleName;
	this.ruleParams = ruleParams;
};

require('util').inherits(Schema.ValidationError, Error);

module.exports = Schema;
<commit_msg>remove excess isRequired condition<commit_after>"use strict";

var _ = require('lodash');
var iterate = require('./lib/iterate');

/**
 * Create instance of Schema
 *
 * @constructors
 * @this {Schema}
 * @class Schema
 * @param {string} [name] - register name
 * @return {Schema}
 */
function Schema (name) {
	if (!(this instanceof Schema)) {
		return new Schema(name);
	}

	if (name != null) {
		Schema.register(name, this);
	}

	this.isRequired = true;
}

Schema.prototype = {

	/**
	 * attach this object to schema
	 *
	 * @method
	 * @param {Schema} schema - attach destination object.
	 * @param {String} name - field name for attach.
	 * @throws {TypeError} If schema isn't Schema type
	 * @throws {TypeError} If name empty or isn't String type
	 * @throws {Error} If schema already has the same key name
	 * @return {Schema} @this
	 */
	attachTo: function (schema, name) {
		if (_.isString(schema)) {
			schema = Schema.get(schema);
		}

		if (!(schema instanceof Schema)) {
			throw new TypeError('schema node must be instance of Schema');
		}

		if (!name || !_.isString(name)) {
			throw new TypeError('invalid scheme field name must be non-empty string, "' + name + '" ' + Object.prototype.toString.call(name) + ' given');
		}

		this.name = name;
		this.path = (schema.path || []).concat(name);

		schema._addField(this, name);

		schema = null;

		return this;
	},

	/**
	 * @private
	 * @method
	 * @param {Schema} schema - attach destination object.
	 * @param {String} name - field name for attach.
	 * @throws {Error} If schema already has the same key name
	 * @return {Schema} @this
	 */
	_addField: function (schema, name) {
		if (!this.keys) {
			this.keys = [];
		} else if (_.contains(this.keys, name)) {
			throw new Error('duplicate key "' + name + '" at "/' + (schema.path && schema.path.join('/')) + '"');
		}

		this.hasNested = true;

		this.keys.push(name);

		if (!this.fields) {
			this.fields = [];
		}

		this.fields.push(schema);
		schema = null;

		return this;
	},

	/**
	 * set validate options. can be called several times
	 *
	 * @method
	 * @param {Array|Object|String|Function} validation - validation options.
	 * @return {Schema} @this
	 */
	validate: function (validation) {
		if (validation) {
			if (!this.validations) {
				this.validations = [];
			}

			if (!_.isArray(validation)) {
				this.validations.push(validation);
			} else {
				this.validations = this.validations.concat(validation);
			}
		}

		return this;
	},

	/**
	 * set nested fields builder
	 *
	 * @method
	 * @param {Function|Schema} builderOrSchema - builder function, has two functions in arguments [required, options].
	 * @throws {TypeError} If nested is not a function if specified
	 * @return {Schema} @this
	 */
	object: function (builderOrSchema) {
		if (this.hasNested) {
			throw new Error('object already defined');
		}

		if (builderOrSchema instanceof Schema) {
			return this._similar(builderOrSchema);
		}

		if (!_.isFunction(builderOrSchema)) {
			throw new TypeError('nested builder must be function');
		}

		builderOrSchema.call(this, this.required.bind(this), this.optional.bind(this));

		return this;
	},

	/**
	 * set nested fields builder with type array
	 *
	 * @method
	 * @param {Function|Schema|Boolean} builderOrSchema - builder function, has two functions in arguments [required, options].
	 * @throws {TypeError} If nested is not a function if specified
	 * @return {Schema} @this
	 */
	array: function (builderOrSchema) {
		if (_.isFunction(builderOrSchema) || builderOrSchema instanceof Schema) {
			this.object(builderOrSchema);
		}

		this.isArray = builderOrSchema == null ? true : Boolean(builderOrSchema);

		return this;
	},

	/**
	 * add new nested schema by construct
	 *
	 * @method
	 * @param {String} name - field name.
	 * @return {Schema} @this
	 */
	field: function (name) {
		return new Schema().attachTo(this, name);
	},

	/**
	 * clone this schema
	 *
	 * @method
	 * @return {Schema} new object (clone)
	 */
	clone: function () {
		var clone = new Schema()._similar(this);

		if (this.isArray != null) {
			clone.isArray = this.isArray;
		}

		return clone;
	},

	//clean: function () {
	//	var clone = new Schema();
	//
	//	_.each(this.fields, function (fieldSchema) {
	//		fieldSchema.clean().attachTo(clone, fieldSchema.name);
	//	});
	//
	//	if (this.isArray != null) {
	//		clone.isArray = this.isArray;
	//	}
	//
	//	if (this.isRequired != null) {
	//		clone.isRequired = this.isRequired;
	//	}
	//},

	/**
	 * clone schema to this schema object
	 *
	 * @private
	 * @method
	 * @return {Schema} new object (clone)
	 */
	_similar: function (schema) {
		var that = this;

		_.each(schema.fields, function (fieldSchema) {
			fieldSchema.clone().attachTo(that, fieldSchema.name);
		});

		if (schema.validations != null) {
			this.validations = _.cloneDeep(schema.validations);
		}

		if (schema.isRequired != null) {
			this.isRequired = schema.isRequired;
		}

		return this;
	},

	/**
	 * verify value. compare schema with some object.
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check.
	 * @param {Object} [options] - validation options, default is plain object.
	 * @param {Function} done - done-callback.
	 */
	verify: function (value, options, done) {
		if (_.isFunction(options)) {
			done = options;
			options = null;
		}

		options || (options = {});

		if (!_.isFunction(done)) {
			throw new Error('schema verify callback must be function, ' + (typeof done) + ' given');
		}

		var that = this;

		var _done = function (err) {
			if (err instanceof Schema.ValidationError) {
				done(null, false, err);
				return;
			}

			if (err) {
				done(err, false, null);
				return;
			}

			done(null, true, null);
		};

		if (value === undefined) {
			if (this.isRequired) {
				_done(new Schema.ValidationError('required', null, this.path, value));
				return;
			}

			_done();
			return;
		}

		var validations = this.validations;
		if (!_.isEmpty(validations)) {
			if (options.validator) {
				validations = options.validator(validations);
			}

			iterate(validations, function (validation, index, done) {
				validation(value, function (err, isValid, validationError) {
					validationError || (validationError = {});

					if (err) {
						done(err);
						return;
					}

					if (!isValid) {
						done(new Schema.ValidationError(validationError.ruleName, validationError.ruleParams, that.path, value));
						return;
					}

					done(null);
				});
			}, function (err) {
				if (err) {
					done(err);
					return;
				}

				that._validationInner(value, options, _done);
			});
			return;
		}

		that._validationInner(value, options, _done);
	},

	/**
	 * verify inner object
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check
	 * @param {Object} options - validation options
	 * @param {Function} done - done-callback
	 */
	_validationInner: function (value, options, done) {
		var that = this;

		if (Boolean(this.isArray) !== _.isArray(value)) {
			done(new Schema.ValidationError('type', this.isArray ? 'array' : 'object', this.path, value));
			return;
		}

		if (this.isArray) {
			iterate(value, function (value, index, done) {
				that._validateFields(value, options, done);
			}, done);

			return;
		}

		that._validateFields(value, options, done);
	},

	/**
	 * verify inner fields
	 *
	 * @private
	 * @method
	 * @param {*} value - value for check
	 * @param {Object} options - validation options
	 * @param {Function} done - done-callback
	 */
	_validateFields: function (value, options, done) {
		if (!this.hasNested) {
			done();
			return;
		}

		if (!_.isObject(value)) {
			done(new Schema.ValidationError('type', 'object', this.path, value));
			return;
		}

		var diff = _.difference(_.keys(value), this.keys);
		if (diff.length) {
			done(new Schema.ValidationError('unexpected_keys', null, this.path, value));
			return;
		}

		iterate(this.fields, function (fieldSchema, index, done) {
			var fieldValue = value[fieldSchema.name];
			fieldSchema.verify(fieldValue, options, function (err, isValid, validationError) {
				err = err || validationError;
				if (err) {
					done(err);
					return;
				}

				if (isValid == null || isValid) {
					done();
					return;
				}

				done(new Schema.ValidationError(null, null, fieldSchema.path, fieldValue));
			});
		}, done);
	},

	/**
	 * add new required nested schema by construct
	 *
	 * @method
	 * @param {String} [name] - field name.
	 * @param {*} [validation] - validation options.
	 * @return {Schema}
	 */
	required: function (name, validation) {
		if (!arguments.length) {
			this.isRequired = true;
			return this;
		}

		return this.field(name).validate(validation);
	},

	/**
	 * add new optional nested schema by construct
	 *
	 * @method
	 * @param {String} [name] - field name.
	 * @param {*} [validation] - validation options.
	 * @return {Schema}
	 */
	optional: function (name, validation) {
		if (!arguments.length) {
			this.isRequired = false;
			return this;
		}

		var schema = this.field(name).validate(validation);
		schema.isRequired = false;
		return schema;
	}
};

var register = {};

/**
 * Schema register
 *
 * @static
 * @param {String} name - name for register.
 * @param {Schema} schema - schema for register
 * @throws {TypeError} If invalid name type
 * @throws {TypeError} If schema name type
 * @throws {ReferenceError} If schema was already registered
 * @return {Schema}
 */
Schema.register = function (name, schema) {
	if (!_.isString(name)) {
		throw new TypeError('invalid name type, must be string');
	}

	if (!(schema instanceof Schema)) {
		throw new TypeError('invalid schema type, must be instance of Schema');
	}

	if (register.hasOwnProperty(name)) {
		throw new ReferenceError('schema "' + name + '" was already registered');
	}

	register[name] = schema;
	return schema;
};

/**
 * get registered schema
 *
 * @static
 * @param {String} name - name for register.
 * @throws {TypeError} If invalid name type
 * @throws {ReferenceError} If schema was not registered before
 * @return {Schema}
 */
Schema.get = function (name) {
	if (!_.isString(name)) {
		throw new TypeError('invalid name type, must be string');
	}

	if (!register.hasOwnProperty(name)) {
		throw new ReferenceError('schema "' + name + '" was not registered');
	}

	return register[name];
};

Schema.errorMessageMap = {};
Schema.errorMessage = function (ruleName, ruleParams, path, value) {
	var map = Schema.errorMessageMap[ruleName];
	return map ? map(ruleName, ruleParams, path, value) : 'invalid value ' + ruleName + ' in ' + path;
};

/**
 * Create instance of Schema.ValidationError. Error object for info about miss value
 *
 * @constructors
 * @this {Schema.ValidationError}
 * @class Schema.ValidationError
 * @param {string} ruleName - rule name, that failed
 * @param {*} ruleParams - params of rule, that failed
 * @param {Array|null} path -  schema path
 * @param {*} value - value, that failed
 * @return {Schema.ValidationError}
 */
Schema.ValidationError = function ValidationError (ruleName, ruleParams, path, value) {
	if (!(this instanceof ValidationError)) {
		return new Schema.ValidationError(ruleName, ruleParams, path, value);
	}

	ruleName || (ruleName = 'unknown');
	path || (path = []);
	value = _.cloneDeep(value);

	var message = Schema.errorMessage(ruleName, ruleParams, path, value);
	Error.call(this, message);
	this.message = message;
	this.type = this.name = 'ValidationError';
	this.value = value;
	this.path = path;
	this.ruleName = ruleName;
	this.ruleParams = ruleParams;
};

require('util').inherits(Schema.ValidationError, Error);

module.exports = Schema;
<|endoftext|>


<commit_before>var debugOut = require('debug')('syncBack')

module.exports = function (opt) {
	var { debug } = opt || {}

	return function (f, back) {
		var api = {
			next: function (err, data) {
				if (err) {
					_debugOut(err)
					fx.throw(err)
				}

				step(data)
			}
		}
		var fx = f(api)
		step()

		function step(data) {
			setTimeout(function () {
				try {
					var c = fx.next(data)
					if (c.done == true)
						_back(null, c.value)
				} catch (err) {
					_debugOut(err)
					_back(err)
				}
			}, 0)
		}
		function _back(err, data) {
			if (back != null)
				back(err, data)
		}
		function _debugOut(err) {
			if (debug)
				debugOut(err)
		}
	}
}<commit_msg>增加一个nextOne<commit_after>var debugOut = require('debug')('syncBack')

module.exports = function (opt) {
	var { debug } = opt || {}

	return function (f, back) {
		var api = {
			next: function (err, data) {
				if (err) {
					_debugOut(err)
					fx.throw(err)
				}

				step(data)
			},
			nextOne: function (data) {
				step(data)
			}
		}
		var fx = f(api)
		step()

		function step(data) {
			setTimeout(function () {
				try {
					var c = fx.next(data)
					if (c.done == true)
						_back(null, c.value)
				} catch (err) {
					_debugOut(err)
					_back(err)
				}
			}, 0)
		}
		function _back(err, data) {
			if (back != null)
				back(err, data)
		}
		function _debugOut(err) {
			if (debug)
				debugOut(err)
		}
	}
}<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var _ = require('lodash'),
	util = require('util'),
	rc = require('rc');

/**
 * Captains Log
 *
 * @param {Object} overrides
 *
 * @option {Object} custom			[overrides Winston if specified]
 * @option {Array} transports		[array of already-configured&instantiated Winston transports-- overrides the defaults!!!]
 * @option {Object} logLevels		[optional - log levels object for winston.setLevels, defaults to npm conventions]
 * @option {String} level			[silly, verbose, info, debug, warn, error, or silent]
 * @option {Boolean} inspect		[defaults to true-- whether to make the log output more readable (combines all args into one string)]
 *
 */

var DEFAULT_OPTIONS = {
	level: 'info',
	inspect: true,
	logLevels: {
		silly: 0,
		verbose: 1,
		info: 2,
		debug: 3,
		warn: 4,
		error: 5,
		// crit: 6,
		// emerg: 6,
		// fail: 6,
		silent: 7
	}
};

// Look for options in `.captainlogrc` files and CAPTAINSLOG-* env variables.
// More on `rc`:  https://github.com/dominictarr/rc#standards
var RC_APPNAME = 'captainslog';

/**
 *
 * Default logger = Winston
 * ====================================
 *
 * By default, this module encapsulates Winston, a popular logger
 * by @indexzero and the gals/guys over at Nodejitsu.
 *
 * More info/docs on Winston:
 * https://github.com/flatiron/winston
 *
 */

/**
 *
 * Using your own custom logger
 * ====================================
 *
 * To use a library other than Winstone, `overrides.custom` must be
 * passed in with, at minimum, an n-ary `log` method, e.g.:
 *
 * var log = new CaptainsLog({}, someLogger);
 * log.log()
 * log.log('blah')
 * log.log('blah', 'foo')
 * log.log('blah', 'foo', {bar: 'baz'})
 * log.log('blah', 'foo', {bar: 'baz'}, ['a', 3], 2, false);
 * // etc.
 */

module.exports = function CaptainsLog ( overrides ) {
	var self = this;

	// Grab winston inside of the constructor just to be safe.
	// (since it seems to maintain some global state)
	var winston = require('winston');

	// Options passed in programmatically are highest priority.
	if (typeof overrides !== 'object') { overrides = {}; }
	var options = _.cloneDeep(overrides);
	// Then `rc` configuration conventions.
	// (https://github.com/dominictarr/rc#standards)
	var rconf = rc(RC_APPNAME);
	rconf.level = rconf.level ||  // Accept command-line shortcuts:
	rconf.verbose ? 'verbose' :   // --verbose
	rconf.silent ? 'silent' :     // --silent
	rconf.silly ? 'silly' :       // --silly
	undefined;
	// Then the implicit defaults. (DEFAULT_OPTIONS above)
	_.defaults(options, rconf, DEFAULT_OPTIONS);

	// Tranports
	//
	// NOTE:
	// Custom transports may be registed by passing them in
	// the `options.transports` config.  However, this approach
	// will replace the built-in transports, so use w/ care.
	if (	options.transports &&
			!_.isArray(options.transports)
		) {
		throw new Error('Invalid `options.transports`.\n\n' +
			'Should be an array of instantiated Winston transports, e.g.:\n' +
			'new (winston.transports.Console)({' + '\n' +
		    '  level: "silly",' + '\n' +
		    '  colorize: "true",' + '\n' +
		    '  label: "foo"' + '\n' +
		    '}),' + '\n' +
		    'new (winston.transports.File)({' + '\n' +
		    '  filename: "/path/to/some/file"' + '\n' +
		    '})'
		);
	}

	// Default transports
	if ( !options.transports ) {

		var consoleOptions = _.extend({
			json: false,
			colorize: true,
			timestamp: false
		}, options);

		// Build the transports array
		options.transports = [
			new (winston.transports.Console)(consoleOptions)
		];

		// TODO:
		// Consider adding default file log in the future.
		// (would need to figure out where to stream them)
		//
		// file: {
		// 	json: true,
		// 	colorize: false,
		// 	timestamp: true,
		// 	maxSize: 10000000,
		// 	maxFiles: 10
		// }
	}

	var logger;

	// If a logger override was specified, use it.
	if ( options.custom ) {
		logger = options.custom;

		// Make sure all supported log methods exist

		// We assume that at least something called
		// `logger.log` exists.
		if (!logger.log) {
			throw new Error(
				'Unsupported logger override!\n' +
				'(has no `.log()` method.)'
			);
		}

		// Fill in the gaps for the log methods
		// used by Sails core in case they're missing.
		logger.debug = logger.debug || logger.log;
		logger.info = logger.info || logger.log;
		logger.warn = logger.warn || logger.error || logger.log;
		logger.error = logger.error || logger.log;
		logger.verbose = logger.verbose || logger.log;
		logger.silly = logger.silly || logger.log;

		// Return logger
		return _buildLogger(logger);
	}

	// No override was specified, so we'll use winston.

	// Instantiate logger
	logger = new (winston.Logger)({
		levels: options.logLevels,
		transports: options.transports
	});

	// Return callable version of core logger
	return _buildLogger(logger);

	/**
	 * Return a special version of `logger` which may
	 * be called directly as a function (implicitly calls
	 * `logger.debug` behind the scenes)
	 *
	 * @param  {Object} logger [original logger]
	 * @return {Function}      [callable logger]
	 * @api private
	 */
	function _buildLogger( logger ) {

		// Make base logger callable (debug)
		var _logger = _inspect(logger.debug);

		// Mix-in log methods, but run `_inspect`
		// on their arguments to improve the readability
		// of log output.
		_logger.error = _inspect(logger.error);
		_logger.warn = _inspect(logger.warn);
		_logger.debug = _inspect(logger.debug);
		_logger.info = _inspect(logger.info);
		_logger.verbose = _inspect(logger.verbose);
		_logger.silly = _inspect(logger.silly);

		return _logger;
	}

	/**
	 * Build a log function which combines arguments into a string,
	 * enhancing them for readability.
	 *
	 * TODO: make this behavior configurable in `options`
	 * in the future (possibly on a per-transport basis)
	 *
	 * @return {Function} [log fn]
	 * @api private
	 */
	function _inspect( logFn ) {
		return function () {
			var args = Array.prototype.slice.call(arguments);

			// If options.inspect is disabled, just call the log fn normally
			if ( ! options.inspect ) {
				return logFn.apply(logFn, args);
			}

			// Compose `str` of all the arguments
			var pieces = [];
			var str = '';
			_.each(arguments, function(arg) {
				if (typeof arg === 'object') {
					if (arg instanceof Error) {
						pieces.push(arg.stack);
						return;
					}
					pieces.push(util.inspect(arg));
					return;
				}

				if (typeof arg === 'function') {
					pieces.push(arg.valueOf());
					return;
				}

				pieces.push(arg);
			});
			str = pieces.join(' ');

			// Call log fn
			return logFn.apply(logFn, [str]);
		};
	}

};

	// Hmm.. this approach doesn't seem to work:
	//
	// Register available transports, adding a category called 'sails'.
	// winston.loggers.add('sails', options.transports);
	// Instantiate a logger.  We'll call it the `sails` logger.
	// logger = winston.loggers.get('sails');

	// Ensure levels on the winston logger
	// are configured to use npm conventions.

	// Here are the log levels, for reference:
	/*
	{
		silly: 0,
		verbose: 1,
		info: 2,
		debug: 3,
		warn: 4,
		error: 5
	}
	*/

	// TODO: wtf winston??? what is going on here??
	// (the built-in `npm` levels don't seem to match npm's
	// documentation)
	//
	// logger.setLevels(options.logLevels || winston.config.npm.levels);
	//

	// new (winston.Logger)({
	// 	transports: transports
	// });

	// Now generate the configured logging methods:

	// Supported log methods
	// var log = _generateLogFn('debug');
	// log.log = _generateLogFn('debug');
	// log.error = _generateLogFn('error');
	// log.warn = _generateLogFn('warn');
	// log.debug = _generateLogFn('debug');
	// log.info = _generateLogFn('info');
	// log.verbose = _generateLogFn('verbose');
	// log.silly = _generateLogFn('silly');

	// Export logger object
	// return log;

	/**
	 * @returns a configured-level-aware log function
	 *          at the specified log level
	 */

	// function _generateLogFn(level) {
	// 	return function() {

	// 		var fn = logger[level];
	// 		fn(str);
	// 	};
	// }
	//
	//
	//
	//
	// If filePath option is set, ALSO write log output to a flat file
	// if (!_.isUndefined(options.filePath)) {
	// 	transports.push(
	// 		new(winston.transports.File)({
	// 			filename: options.filePath,
	// 			maxsize: options.maxSize,
	// 			maxFiles: options.maxFiles,
	// 			level: options.level,
	// 			json: options.json,
	// 			colorize: false,
	// 			stripColors: true
	// 		}));
	// }

	// // Winston's log levels
	// var winstonLogLevels = {
	//     silly: 0,
	//     verbose: 1,
	//     info: 2,
	//     notice: 2,
	//     debug: 3,
	//     alert: 4,
	//     warn: 4,
	//     warning: 4,
	//     error: 5,
	//     crit: 6,
	//     emerg: 6,
	//     fail: 6,
	//     silent: 7
	// };

	// // Colors to use for various log levels
	// var logColors = {
	//     silly: 'cyan',
	//     verbose: 'cyan',
	//     info: 'green',
	//     notice: 'green',
	//     debug: 'blue',
	//     alert: 'yellow',
	//     warn: 'yellow',
	//     warning: 'yellow',
	//     error: 'red',
	//     crit: 'red',
	//     emerg: 'red',
	//     fail: 'red',
	//     silent: 'white'
	// };

	// if adapter option is set, ALSO write log output to an adapter
	// if (!_.isUndefined(options.adapters)) {
	// 	_.each(options.adapters, function(val, transport) {
	// 		if (typeof val.module !== 'undefined') {

	// 			// The winston module MUST be exported to a variable of same name
	// 			var module = require(val.module)[transport];

	// 			// Make sure it was exported correctly
	// 			if (module) {
	// 				transports.push(
	// 					new(module)(val)
	// 				);
	// 			}
	// 		}
	// 	});
	// }

<commit_msg>Made appName configurable (for rc- loading env variables, rc config files, etc.)<commit_after>/**
 * Module dependencies.
 */

var _ = require('lodash'),
	util = require('util'),
	rc = require('rc');

/**
 * Captains Log
 *
 * @param {Object} overrides
 *
 * @option {Object} custom			[overrides Winston if specified]
 * @option {Array} transports		[array of already-configured&instantiated Winston transports-- overrides the defaults!!!]
 * @option {Object} logLevels		[optional - log levels object for winston.setLevels, defaults to npm conventions]
 * @option {String} level			[silly, verbose, info, debug, warn, error, or silent]
 * @option {Boolean} inspect		[defaults to true-- whether to make the log output more readable (combines all args into one string)]
 *
 */

var DEFAULT_OPTIONS = {
	level: 'info',
	inspect: true,
	logLevels: {
		silly: 0,
		verbose: 1,
		info: 2,
		debug: 3,
		warn: 4,
		error: 5,
		// crit: 6,
		// emerg: 6,
		// fail: 6,
		silent: 7
	},

	// By default, look for options in:
	//   + `.captainlogrc` files
	//   + `CAPTAINSLOG-*` env variables
	//
	// More on `rc` conventions:
	// https://github.com/dominictarr/rc#standards
	appName: 'captainslog'
};

/**
 *
 * Default logger = Winston
 * ====================================
 *
 * By default, this module encapsulates Winston, a popular logger
 * by @indexzero and the gals/guys over at Nodejitsu.
 *
 * More info/docs on Winston:
 * https://github.com/flatiron/winston
 *
 */

/**
 *
 * Using your own custom logger
 * ====================================
 *
 * To use a library other than Winstone, `overrides.custom` must be
 * passed in with, at minimum, an n-ary `log` method, e.g.:
 *
 * var log = new CaptainsLog({}, someLogger);
 * log.log()
 * log.log('blah')
 * log.log('blah', 'foo')
 * log.log('blah', 'foo', {bar: 'baz'})
 * log.log('blah', 'foo', {bar: 'baz'}, ['a', 3], 2, false);
 * // etc.
 */

module.exports = function CaptainsLog ( overrides ) {
	var self = this;

	// Grab winston inside of the constructor just to be safe.
	// (since it seems to maintain some global state)
	var winston = require('winston');

	// Options passed in programmatically are highest priority.
	if (typeof overrides !== 'object') { overrides = {}; }
	var options = _.cloneDeep(overrides);
	// Then `rc` configuration conventions.
	// (https://github.com/dominictarr/rc#standards)
	var rconf = rc(overrides.appName);
	rconf.level = rconf.level ||  // Accept command-line shortcuts:
	rconf.verbose ? 'verbose' :   // --verbose
	rconf.silent ? 'silent' :     // --silent
	rconf.silly ? 'silly' :       // --silly
	undefined;
	// Then the implicit defaults. (DEFAULT_OPTIONS above)
	_.defaults(options, rconf, DEFAULT_OPTIONS);

	// Tranports
	//
	// NOTE:
	// Custom transports may be registed by passing them in
	// the `options.transports` config.  However, this approach
	// will replace the built-in transports, so use w/ care.
	if (	options.transports &&
			!_.isArray(options.transports)
		) {
		throw new Error('Invalid `options.transports`.\n\n' +
			'Should be an array of instantiated Winston transports, e.g.:\n' +
			'new (winston.transports.Console)({' + '\n' +
		    '  level: "silly",' + '\n' +
		    '  colorize: "true",' + '\n' +
		    '  label: "foo"' + '\n' +
		    '}),' + '\n' +
		    'new (winston.transports.File)({' + '\n' +
		    '  filename: "/path/to/some/file"' + '\n' +
		    '})'
		);
	}

	// Default transports
	if ( !options.transports ) {

		var consoleOptions = _.extend({
			json: false,
			colorize: true,
			timestamp: false
		}, options);

		// Build the transports array
		options.transports = [
			new (winston.transports.Console)(consoleOptions)
		];

		// TODO:
		// Consider adding default file log in the future.
		// (would need to figure out where to stream them)
		//
		// file: {
		// 	json: true,
		// 	colorize: false,
		// 	timestamp: true,
		// 	maxSize: 10000000,
		// 	maxFiles: 10
		// }
	}

	var logger;

	// If a logger override was specified, use it.
	if ( options.custom ) {
		logger = options.custom;

		// Make sure all supported log methods exist

		// We assume that at least something called
		// `logger.log` exists.
		if (!logger.log) {
			throw new Error(
				'Unsupported logger override!\n' +
				'(has no `.log()` method.)'
			);
		}

		// Fill in the gaps for the log methods
		// used by Sails core in case they're missing.
		logger.debug = logger.debug || logger.log;
		logger.info = logger.info || logger.log;
		logger.warn = logger.warn || logger.error || logger.log;
		logger.error = logger.error || logger.log;
		logger.verbose = logger.verbose || logger.log;
		logger.silly = logger.silly || logger.log;

		// Return logger
		return _buildLogger(logger);
	}

	// No override was specified, so we'll use winston.

	// Instantiate logger
	logger = new (winston.Logger)({
		levels: options.logLevels,
		transports: options.transports
	});

	// Return callable version of core logger
	return _buildLogger(logger);

	/**
	 * Return a special version of `logger` which may
	 * be called directly as a function (implicitly calls
	 * `logger.debug` behind the scenes)
	 *
	 * @param  {Object} logger [original logger]
	 * @return {Function}      [callable logger]
	 * @api private
	 */
	function _buildLogger( logger ) {

		// Make base logger callable (debug)
		var _logger = _inspect(logger.debug);

		// Mix-in log methods, but run `_inspect`
		// on their arguments to improve the readability
		// of log output.
		_logger.error = _inspect(logger.error);
		_logger.warn = _inspect(logger.warn);
		_logger.debug = _inspect(logger.debug);
		_logger.info = _inspect(logger.info);
		_logger.verbose = _inspect(logger.verbose);
		_logger.silly = _inspect(logger.silly);

		return _logger;
	}

	/**
	 * Build a log function which combines arguments into a string,
	 * enhancing them for readability.
	 *
	 * TODO: make this behavior configurable in `options`
	 * in the future (possibly on a per-transport basis)
	 *
	 * @return {Function} [log fn]
	 * @api private
	 */
	function _inspect( logFn ) {
		return function () {
			var args = Array.prototype.slice.call(arguments);

			// If options.inspect is disabled, just call the log fn normally
			if ( ! options.inspect ) {
				return logFn.apply(logFn, args);
			}

			// Compose `str` of all the arguments
			var pieces = [];
			var str = '';
			_.each(arguments, function(arg) {
				if (typeof arg === 'object') {
					if (arg instanceof Error) {
						pieces.push(arg.stack);
						return;
					}
					pieces.push(util.inspect(arg));
					return;
				}

				if (typeof arg === 'function') {
					pieces.push(arg.valueOf());
					return;
				}

				pieces.push(arg);
			});
			str = pieces.join(' ');

			// Call log fn
			return logFn.apply(logFn, [str]);
		};
	}

};

	// Hmm.. this approach doesn't seem to work:
	//
	// Register available transports, adding a category called 'sails'.
	// winston.loggers.add('sails', options.transports);
	// Instantiate a logger.  We'll call it the `sails` logger.
	// logger = winston.loggers.get('sails');

	// Ensure levels on the winston logger
	// are configured to use npm conventions.

	// Here are the log levels, for reference:
	/*
	{
		silly: 0,
		verbose: 1,
		info: 2,
		debug: 3,
		warn: 4,
		error: 5
	}
	*/

	// TODO: wtf winston??? what is going on here??
	// (the built-in `npm` levels don't seem to match npm's
	// documentation)
	//
	// logger.setLevels(options.logLevels || winston.config.npm.levels);
	//

	// new (winston.Logger)({
	// 	transports: transports
	// });

	// Now generate the configured logging methods:

	// Supported log methods
	// var log = _generateLogFn('debug');
	// log.log = _generateLogFn('debug');
	// log.error = _generateLogFn('error');
	// log.warn = _generateLogFn('warn');
	// log.debug = _generateLogFn('debug');
	// log.info = _generateLogFn('info');
	// log.verbose = _generateLogFn('verbose');
	// log.silly = _generateLogFn('silly');

	// Export logger object
	// return log;

	/**
	 * @returns a configured-level-aware log function
	 *          at the specified log level
	 */

	// function _generateLogFn(level) {
	// 	return function() {

	// 		var fn = logger[level];
	// 		fn(str);
	// 	};
	// }
	//
	//
	//
	//
	// If filePath option is set, ALSO write log output to a flat file
	// if (!_.isUndefined(options.filePath)) {
	// 	transports.push(
	// 		new(winston.transports.File)({
	// 			filename: options.filePath,
	// 			maxsize: options.maxSize,
	// 			maxFiles: options.maxFiles,
	// 			level: options.level,
	// 			json: options.json,
	// 			colorize: false,
	// 			stripColors: true
	// 		}));
	// }

	// // Winston's log levels
	// var winstonLogLevels = {
	//     silly: 0,
	//     verbose: 1,
	//     info: 2,
	//     notice: 2,
	//     debug: 3,
	//     alert: 4,
	//     warn: 4,
	//     warning: 4,
	//     error: 5,
	//     crit: 6,
	//     emerg: 6,
	//     fail: 6,
	//     silent: 7
	// };

	// // Colors to use for various log levels
	// var logColors = {
	//     silly: 'cyan',
	//     verbose: 'cyan',
	//     info: 'green',
	//     notice: 'green',
	//     debug: 'blue',
	//     alert: 'yellow',
	//     warn: 'yellow',
	//     warning: 'yellow',
	//     error: 'red',
	//     crit: 'red',
	//     emerg: 'red',
	//     fail: 'red',
	//     silent: 'white'
	// };

	// if adapter option is set, ALSO write log output to an adapter
	// if (!_.isUndefined(options.adapters)) {
	// 	_.each(options.adapters, function(val, transport) {
	// 		if (typeof val.module !== 'undefined') {

	// 			// The winston module MUST be exported to a variable of same name
	// 			var module = require(val.module)[transport];

	// 			// Make sure it was exported correctly
	// 			if (module) {
	// 				transports.push(
	// 					new(module)(val)
	// 				);
	// 			}
	// 		}
	// 	});
	// }

<|endoftext|>


<commit_before>
var EventEmitter = require('events').EventEmitter
var next         = process.nextTick
var SubDb        = require('./sub')

var Hooks   = require('level-hooks')

module.exports   = function (db, sep) {
  //use \xff (255) as the seperator,
  //so that sections of the database will sort after the regular keys
  sep = sep || '\xff'
  Hooks(db)

  db.sublevel = function (prefix) {
    return new SubDb(db, prefix, sep)
  }

  db.prefix = function () {
    return ''
  }

  db.pre = function (hook) {
    r.hooks.pre({
        start: '',
        end  : sep
      }
      , hook)
    return db
  }
  db.post = function (hook) {
    db.hooks.post({start: '', end: sep}, hook)
    return db
  }

  return db
}

<commit_msg>r is not defined<commit_after>
var EventEmitter = require('events').EventEmitter
var next         = process.nextTick
var SubDb        = require('./sub')

var Hooks   = require('level-hooks')

module.exports   = function (db, sep) {
  //use \xff (255) as the seperator,
  //so that sections of the database will sort after the regular keys
  sep = sep || '\xff'
  Hooks(db)

  db.sublevel = function (prefix) {
    return new SubDb(db, prefix, sep)
  }

  db.prefix = function () {
    return ''
  }

  db.pre = function (hook) {
    db.hooks.pre({
        start: '',
        end  : sep
      }
      , hook)
    return db
  }
  db.post = function (hook) {
    db.hooks.post({start: '', end: sep}, hook)
    return db
  }

  return db
}

<|endoftext|>


<commit_before>/**
 * assemble-middleware-wordcount
 * Assemble middleware for rendering the wordcount for
 * the specified section of content.
 *
 * Copyright (c) 2014 Jon Schlinkert
 * Licensed under the MIT License
 */
'use strict';

var cheerio = require('cheerio');
var log = require('verbalize');
var _ = require('lodash');

module.exports = function (assemble) {
  var middleware = function (params, next) {
    var opts  = assemble.config.wordcount || {};

    // See http://onforb.es/1crk3KF
    opts.speed         = opts.speed         || 300;
    opts.seconds       = opts.seconds       || false;
    opts.placement     = opts.placement     || 'prepend';
    opts.selector      = opts.selector      || '.wordcount';
    opts.countSelector = opts.countSelector || '.label-wordcount';
    opts.timeSelector  = opts.timeSelector  || '.label-reading-time';

    // load current page content
    var $ = cheerio.load(params.content);

    if($(opts.selector) && $(opts.selector).length > 0) {
      var countable = $(opts.selector);

      // Strip HTML tags from content
      var content = countable.html().replace(/(<([^>]+)>)/ig, '');

      // Solution from http://drewschrauf.com/blog/2012/06/13/javascript-wordcount-that-works/
      var matches = content.match(/\S+\s*/g);
      var count = matches !== null ? matches.length : 0;

      // Calculate reading time
      var min, mins, sec, secs, est;
      if(opts.seconds === true) {
        min = Math.floor(count / opts.speed);
        sec = Math.floor(count % opts.speed / (opts.speed / 60));
        mins = min + ' minute' + (min === 1 ? '' : 's') + ', ';
        secs = sec + ' second' + (sec === 1 ? '' : 's');
        est = (min > 0) ? mins + secs : secs;
      } else {
        min = Math.ceil(count / opts.speed);
        est = min + ' min';
      }

      // Render wordcount
      $(opts.countSelector).attr('data-wordcount', count);
      $(opts.countSelector)[opts.placement](String(count));

      // Render reading time
      $(opts.timeSelector).attr('data-reading-time', est);
      $(opts.timeSelector)[opts.placement](est);

      params.content = $.html();
    }
    next();
  };

  middleware.event = 'page:after:render';
  return {
    'assemble-middleware-wordcount': middleware
  };
};
<commit_msg>fixing where content was being updated<commit_after>/**
 * assemble-middleware-wordcount
 * Assemble middleware for rendering the wordcount for
 * the specified section of content.
 *
 * Copyright (c) 2014 Jon Schlinkert
 * Licensed under the MIT License
 */
'use strict';

var cheerio = require('cheerio');
var log = require('verbalize');
var _ = require('lodash');

module.exports = function (assemble) {
  var middleware = function (params, next) {
    var opts  = assemble.config.wordcount || {};

    // See http://onforb.es/1crk3KF
    opts.speed         = opts.speed         || 300;
    opts.seconds       = opts.seconds       || false;
    opts.placement     = opts.placement     || 'prepend';
    opts.selector      = opts.selector      || '.wordcount';
    opts.countSelector = opts.countSelector || '.label-wordcount';
    opts.timeSelector  = opts.timeSelector  || '.label-reading-time';

    // load current page content
    var $ = cheerio.load(params.page.content);

    if($(opts.selector) && $(opts.selector).length > 0) {
      var countable = $(opts.selector);

      // Strip HTML tags from content
      var content = countable.html().replace(/(<([^>]+)>)/ig, '');

      // Solution from http://drewschrauf.com/blog/2012/06/13/javascript-wordcount-that-works/
      var matches = content.match(/\S+\s*/g);
      var count = matches !== null ? matches.length : 0;

      // Calculate reading time
      var min, mins, sec, secs, est;
      if(opts.seconds === true) {
        min = Math.floor(count / opts.speed);
        sec = Math.floor(count % opts.speed / (opts.speed / 60));
        mins = min + ' minute' + (min === 1 ? '' : 's') + ', ';
        secs = sec + ' second' + (sec === 1 ? '' : 's');
        est = (min > 0) ? mins + secs : secs;
      } else {
        min = Math.ceil(count / opts.speed);
        est = min + ' min';
      }

      // Render wordcount
      $(opts.countSelector).attr('data-wordcount', count);
      $(opts.countSelector)[opts.placement](String(count));

      // Render reading time
      $(opts.timeSelector).attr('data-reading-time', est);
      $(opts.timeSelector)[opts.placement](est);

      params.page.content = $.html();
    }
    next();
  };

  middleware.event = 'page:after:render';
  return {
    'assemble-middleware-wordcount': middleware
  };
};
<|endoftext|>


<commit_before>var Playback = require('playback')
var JST = require('./jst')

class YoutubePlayback extends Playback {
  get name() { return 'youtube_playback' }

  get attributes() {
    return {
      'data-youtube-playback': '',
      class: 'clappr-youtube-playback',
      id: this.cid
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.settings = {
      seekEnabled: true,
      left: ['playpause', 'position', 'duration'],
      default: ['seekbar'],
      right:['fullscreen','volume', 'hd-indicator']
    }
    Clappr.Mediator.on(Clappr.Events.PLAYER_RESIZE, this.updateSize, this)
  }

  setupYoutubePlayer() {
    if (window.YT && window.YT.Player) {
      this.embedYoutubePlayer()
    } else {
      this.embedYoutubeApiScript()
    }
  }

  embedYoutubeApiScript() {
      var script = document.createElement('script')
      script.setAttribute('type', 'text/javascript')
      script.setAttribute('async', 'async')
      script.setAttribute('src', 'https://www.youtube.com/iframe_api')
      document.body.appendChild(script)
      window.onYouTubeIframeAPIReady = () => this.embedYoutubePlayer()
  }

  embedYoutubePlayer() {
    this.player = new YT.Player(`yt${this.cid}`, {
      videoId: this.options.src,
      playerVars: {
        controls: 0,
        autoplay: 0,
        disablekb: 1,
        enablejsapi: 1,
        iv_load_policy: 3,
        modestbranding: 1,
        showinfo: 0,
        html5: 1
      },
      events: {
        onReady: () => this.ready(),
        onStateChange: (event) => this.stateChange(event),
        onPlaybackQualityChange: (event) => this.qualityChange(event)
      }
    })
  }

  updateSize() {
    this.player && this.player.setSize(this.$el.width(), this.$el.height())
  }

  ready() {
    this._ready = true
    this.trigger(Clappr.Events.PLAYBACK_READY)
  }

  qualityChange(event) {
    this.trigger(Clappr.Events.PLAYBACK_HIGHDEFINITIONUPDATE)
  }

  stateChange(event) {
    switch (event.data) {
      case YT.PlayerState.PLAYING:
        this.trigger(Clappr.Events.PLAYBACK_PLAY)
        break
      default: break
    }
  }

  play() {
    if (this._ready) {
      this._progressTimer = this._progressTimer || setInterval(() => this.progress(), 100)
      this._timeupdateTimer = setInterval(() => this.timeupdate(), 100)
      this.player.playVideo()
      this.trigger(Clappr.Events.PLAYBACK_PLAY)
      this.trigger(Clappr.Events.PLAYBACK_BUFFERFULL)
    } else {
      this.listenToOnce(this, Clappr.Events.PLAYBACK_READY, this.play)
    }
  }

  pause() {
    clearInterval(this._timeupdateTimer)
    this._timeupdateTimer = null
    this.player && this.player.pauseVideo()
  }

  seek(position) {
    if (!this.player) return
    var duration = this.player.getDuration()
    var time = position * duration / 100
    this.player.seekTo(time)
  }

  volume(value) {
    this.player && this.player.setVolume(value)
  }

  progress() {
    var buffered = this.player.getDuration() * this.player.getVideoLoadedFraction()
    this.trigger(Clappr.Events.PLAYBACK_PROGRESS, 0, buffered, this.player.getDuration())
  }

  timeupdate() {
    this.trigger(Clappr.Events.PLAYBACK_TIMEUPDATE, this.player.getCurrentTime(), this.player.getDuration())
  }

  isPlaying() {
    return this.player && this._timeupdateTimer && this.player.getPlayerState() == YT.PlayerState.PLAYING
  }

  isHighDefinitionInUse() {
    return this.player && !!this.player.getPlaybackQuality().match(/^hd\d+/)
  }

  getDuration() {
    var duration = 0
    if (this.player) {
      duration = this.player.getDuration()
    }
    return duration
  }

  render() {
    this.$el.html(JST[this.name]({id: `yt${this.cid}`}))
    var style = $('<style>').html(JST.CSS[this.name])
    this.$el.append(style)
    this.setupYoutubePlayer()
    return this;
  }
}

YoutubePlayback.canPlay = function(source) {
  return true;
};

module.exports = window.YoutubePlayback = YoutubePlayback;
<commit_msg>detect end video to go back into poster screen (closes #6)<commit_after>var Playback = require('playback')
var JST = require('./jst')

class YoutubePlayback extends Playback {
  get name() { return 'youtube_playback' }

  get attributes() {
    return {
      'data-youtube-playback': '',
      class: 'clappr-youtube-playback',
      id: this.cid
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.settings = {
      seekEnabled: true,
      left: ['playpause', 'position', 'duration'],
      default: ['seekbar'],
      right:['fullscreen','volume', 'hd-indicator']
    }
    Clappr.Mediator.on(Clappr.Events.PLAYER_RESIZE, this.updateSize, this)
  }

  setupYoutubePlayer() {
    if (window.YT && window.YT.Player) {
      this.embedYoutubePlayer()
    } else {
      this.embedYoutubeApiScript()
    }
  }

  embedYoutubeApiScript() {
      var script = document.createElement('script')
      script.setAttribute('type', 'text/javascript')
      script.setAttribute('async', 'async')
      script.setAttribute('src', 'https://www.youtube.com/iframe_api')
      document.body.appendChild(script)
      window.onYouTubeIframeAPIReady = () => this.embedYoutubePlayer()
  }

  embedYoutubePlayer() {
    this.player = new YT.Player(`yt${this.cid}`, {
      videoId: this.options.src,
      playerVars: {
        controls: 0,
        autoplay: 0,
        disablekb: 1,
        enablejsapi: 1,
        iv_load_policy: 3,
        modestbranding: 1,
        showinfo: 0,
        html5: 1
      },
      events: {
        onReady: () => this.ready(),
        onStateChange: (event) => this.stateChange(event),
        onPlaybackQualityChange: (event) => this.qualityChange(event)
      }
    })
  }

  updateSize() {
    this.player && this.player.setSize(this.$el.width(), this.$el.height())
  }

  ready() {
    this._ready = true
    this.trigger(Clappr.Events.PLAYBACK_READY)
  }

  qualityChange(event) {
    this.trigger(Clappr.Events.PLAYBACK_HIGHDEFINITIONUPDATE)
  }

  stateChange(event) {
    switch (event.data) {
      case YT.PlayerState.PLAYING:
        this.trigger(Clappr.Events.PLAYBACK_PLAY)
        break
      case YT.PlayerState.ENDED:
        this.trigger(Clappr.Events.PLAYBACK_ENDED)
        break
      default: break
    }
  }

  play() {
    if (this._ready) {
      this._progressTimer = this._progressTimer || setInterval(() => this.progress(), 100)
      this._timeupdateTimer = setInterval(() => this.timeupdate(), 100)
      this.player.playVideo()
      this.trigger(Clappr.Events.PLAYBACK_PLAY)
      this.trigger(Clappr.Events.PLAYBACK_BUFFERFULL)
    } else {
      this.listenToOnce(this, Clappr.Events.PLAYBACK_READY, this.play)
    }
  }

  pause() {
    clearInterval(this._timeupdateTimer)
    this._timeupdateTimer = null
    this.player && this.player.pauseVideo()
  }

  seek(position) {
    if (!this.player) return
    var duration = this.player.getDuration()
    var time = position * duration / 100
    this.player.seekTo(time)
  }

  volume(value) {
    this.player && this.player.setVolume(value)
  }

  progress() {
    var buffered = this.player.getDuration() * this.player.getVideoLoadedFraction()
    this.trigger(Clappr.Events.PLAYBACK_PROGRESS, 0, buffered, this.player.getDuration())
  }

  timeupdate() {
    this.trigger(Clappr.Events.PLAYBACK_TIMEUPDATE, this.player.getCurrentTime(), this.player.getDuration())
  }

  isPlaying() {
    return this.player && this._timeupdateTimer && this.player.getPlayerState() == YT.PlayerState.PLAYING
  }

  isHighDefinitionInUse() {
    return this.player && !!this.player.getPlaybackQuality().match(/^hd\d+/)
  }

  getDuration() {
    var duration = 0
    if (this.player) {
      duration = this.player.getDuration()
    }
    return duration
  }

  render() {
    this.$el.html(JST[this.name]({id: `yt${this.cid}`}))
    var style = $('<style>').html(JST.CSS[this.name])
    this.$el.append(style)
    this.setupYoutubePlayer()
    return this;
  }
}

YoutubePlayback.canPlay = function(source) {
  return true;
};

module.exports = window.YoutubePlayback = YoutubePlayback;
<|endoftext|>


<commit_before>"use strict";
var nodecss = require("node-css"),
  _ = require("lodash"),
  libpath = require("path");

var CSS = nodecss.CSS;
var rxReplacePath = /(\/|\\)/g;
var MEDIA_QUERY = "(min-device-pixel-ratio: 2) and (min-resolution: 192dpi)";
var css = new CSS();

function CSSImage() {
}

CSSImage.prototype.css = function(filepath, width, height, root, options) {
  var classname = "." + this.name(filepath, options);
  if (!options) { options = {}; }
  if (options.retina) {
    options.media = MEDIA_QUERY;
  }
  var squeeze = !!options.squeeze ? +options.squeeze : 1;
  var _width = Math.floor(width / squeeze);
  var _height = Math.floor(height / squeeze);
  return css.statement(classname, {
    width: _width + "px",
    height: _height + "px",
    "background-image": this.url(filepath, root, options.retina),
    "background-size": "" + _width  + "px " + _height + "px"
  }, options);
};

CSSImage.prototype.scssVars = function(filepath, _width, _height, options) {
  var name = this.name(filepath, options);
  var squeeze = (options && !!options.squeeze) ? +options.squeeze : 1;
  var width = Math.floor(_width / squeeze);
  var height = Math.floor(_height / squeeze);
  var root = (options && options.root) || "";
  var retina = options && !!options.retina;
  var fullpath = this.normalizePath(filepath, root, retina);

  return "$" + name + ": (\n" +
         "\twidth: " + width + "px,\n" +
         "\theight: " + height + "px,\n" +
         "\tfullpath: \"" + fullpath + "\",\n" +
         "\tpath: \"" + filepath + "\"\n" +
         ");\n" +
         "$" + name + "__width: " + width + "px;\n" +
         "$" + name + "__height: " + height + "px;\n" +
         "$" + name + "__path: '" + fullpath + "';\n\n";
};

CSSImage.prototype.scssMixin = function(filepath, _width, _height, root, options) {
  var name = this.name(filepath, options);
  if (!options) { options = {}; }
  var classname = "@mixin " + name + "()";
  var isRetina = !!options.retina;
  var indent = css.options(options, "indent");
  var squeeze = (options && !!options.squeeze) ? +options.squeeze : 1;
  var width = Math.floor(_width / squeeze);
  var height = Math.floor(_height / squeeze);

  var scssMixin = css.body({
    width: width + "px",
    height: height + "px",
    "background-image": this.url(filepath, root),
    "background-size": "" + width  + "px " + height + "px"
  }, {indent: indent});

  if (isRetina) {
    var body = css.body({
      width: width + "px",
      height: height + "px",
      "background-image": this.url(filepath, root, options.retina),
      "background-size": "" + width  + "px " + height + "px"
    }, {indent: indent + indent});
    scssMixin += indent + "@media " + MEDIA_QUERY + " {\n" + body + indent + "}\n";
  }
  return classname + " {\n" + scssMixin + "}\n";
};

CSSImage.prototype.scss = function(filepath, width, height, root, options) {
  return this.scssMixin(filepath, width, height, root, options) +
         this.scssVars(filepath, width, height, options);
};

CSSImage.prototype.url = function(filepath, root, retina) {
  return "url(" + this.normalizePath(filepath, root, retina) + ")";
};

CSSImage.prototype.normalizePath = function(filepath, root, retina) {
  var name = libpath.basename(filepath);
  var ext = libpath.extname(filepath);
  if (!!retina) {
    var postfix = (typeof retina === "string") ? retina : "-50pc";
    name = name.replace(ext, postfix + ext);
  }
  var normalizedPath = libpath.join(this.normalizeFolder(filepath, root), name);
  normalizedPath = normalizedPath.replace(rxReplacePath, "/");
  return normalizedPath;
};

CSSImage.prototype.normalizeFolder = function(filepath, root) {
  var folder = libpath.dirname(filepath);
  if (folder[0] === "." && folder[1] !== ".") { folder = folder.slice(1); }
  if (folder[0] === "/") { folder = folder.slice(1); }
  var result = root ? libpath.join(root, folder) : folder;
  return result.replace(rxReplacePath, "/");
};

CSSImage.prototype.name = function(filepath, options) {
  var postfix = options && options.postfix ? options.postfix : "";
  if (options && options.squeeze) { postfix += "-s" + options.squeeze; }
  var prefix = options && (typeof options.prefix !== "undefined") ? options.prefix : "img_";
  var separator = (options && options.separator) || "_";
  var filename = libpath.basename(filepath);
  var ext = libpath.extname(filepath);
  var name = filename.slice(0, filename.length - ext.length).replace(/\./, "");
  var folder = this.normalizeFolder(filepath);
  if (folder === "") { return prefix + name + postfix; }

  // windows fix
  folder = folder.replace(rxReplacePath, separator);
  return prefix + folder + separator + name + postfix;
};

var _cssImage = new CSSImage();
function cssimage(images, _options) {
  var options = _.omit(_options, ["retina", "squeeze"]);
  var isCss = !!options.css;
  var isScss = !!options.scss;
  var root = options.root || "";
  var result = "";
  var isRetina = _options && !!_options.retina;
  var squeeze = (_options && _options.squeeze) || 1;
  for (var i = 0; i < images.length; i++) {
    var img = images[i];
    if (isCss) {
      result += _cssImage.css(img.file, img.width, img.height, root, options);
      if (isRetina) {
        result += _cssImage.css(img.file, img.width, img.height, root, _.extend({
          retina: true
        }, options));
      }
      if (squeeze !== 1) {
        result += _cssImage.css(img.file, img.width, img.height, root, _.extend({
          squeeze: squeeze
        }, options));
      }
    }
    if (isScss) {
      result += _cssImage.scss(img.file, img.width, img.height, root, _.extend({
        retina: isRetina
      }, options));
      if (squeeze !== 1) {
        result += _cssImage.scss(img.file, img.width, img.height, root, _.extend({
          squeeze: squeeze
        }, options));
      }
    }
  }
  return result;
}

module.exports = cssimage;
module.exports.CSSImage = CSSImage;
<commit_msg>Added quotes to url()<commit_after>"use strict";
var nodecss = require("node-css"),
  _ = require("lodash"),
  libpath = require("path");

var CSS = nodecss.CSS;
var rxReplacePath = /(\/|\\)/g;
var MEDIA_QUERY = "(min-device-pixel-ratio: 2) and (min-resolution: 192dpi)";
var css = new CSS();

function CSSImage() {
}

CSSImage.prototype.css = function(filepath, width, height, root, options) {
  var classname = "." + this.name(filepath, options);
  if (!options) { options = {}; }
  if (options.retina) {
    options.media = MEDIA_QUERY;
  }
  var squeeze = !!options.squeeze ? +options.squeeze : 1;
  var _width = Math.floor(width / squeeze);
  var _height = Math.floor(height / squeeze);
  return css.statement(classname, {
    width: _width + "px",
    height: _height + "px",
    "background-image": this.url(filepath, root, options.retina),
    "background-size": "" + _width  + "px " + _height + "px"
  }, options);
};

CSSImage.prototype.scssVars = function(filepath, _width, _height, options) {
  var name = this.name(filepath, options);
  var squeeze = (options && !!options.squeeze) ? +options.squeeze : 1;
  var width = Math.floor(_width / squeeze);
  var height = Math.floor(_height / squeeze);
  var root = (options && options.root) || "";
  var retina = options && !!options.retina;
  var fullpath = this.normalizePath(filepath, root, retina);

  return "$" + name + ": (\n" +
         "\twidth: " + width + "px,\n" +
         "\theight: " + height + "px,\n" +
         "\tfullpath: \"" + fullpath + "\",\n" +
         "\tpath: \"" + filepath + "\"\n" +
         ");\n" +
         "$" + name + "__width: " + width + "px;\n" +
         "$" + name + "__height: " + height + "px;\n" +
         "$" + name + "__path: '" + fullpath + "';\n\n";
};

CSSImage.prototype.scssMixin = function(filepath, _width, _height, root, options) {
  var name = this.name(filepath, options);
  if (!options) { options = {}; }
  var classname = "@mixin " + name + "()";
  var isRetina = !!options.retina;
  var indent = css.options(options, "indent");
  var squeeze = (options && !!options.squeeze) ? +options.squeeze : 1;
  var width = Math.floor(_width / squeeze);
  var height = Math.floor(_height / squeeze);

  var scssMixin = css.body({
    width: width + "px",
    height: height + "px",
    "background-image": this.url(filepath, root),
    "background-size": "" + width  + "px " + height + "px"
  }, {indent: indent});

  if (isRetina) {
    var body = css.body({
      width: width + "px",
      height: height + "px",
      "background-image": this.url(filepath, root, options.retina),
      "background-size": "" + width  + "px " + height + "px"
    }, {indent: indent + indent});
    scssMixin += indent + "@media " + MEDIA_QUERY + " {\n" + body + indent + "}\n";
  }
  return classname + " {\n" + scssMixin + "}\n";
};

CSSImage.prototype.scss = function(filepath, width, height, root, options) {
  return this.scssMixin(filepath, width, height, root, options) +
         this.scssVars(filepath, width, height, options);
};

CSSImage.prototype.url = function(filepath, root, retina) {
  return "url(\"" + this.normalizePath(filepath, root, retina) + "\")";
};

CSSImage.prototype.normalizePath = function(filepath, root, retina) {
  var name = libpath.basename(filepath);
  var ext = libpath.extname(filepath);
  if (!!retina) {
    var postfix = (typeof retina === "string") ? retina : "-50pc";
    name = name.replace(ext, postfix + ext);
  }
  var normalizedPath = libpath.join(this.normalizeFolder(filepath, root), name);
  normalizedPath = normalizedPath.replace(rxReplacePath, "/");
  return normalizedPath;
};

CSSImage.prototype.normalizeFolder = function(filepath, root) {
  var folder = libpath.dirname(filepath);
  if (folder[0] === "." && folder[1] !== ".") { folder = folder.slice(1); }
  if (folder[0] === "/") { folder = folder.slice(1); }
  var result = root ? libpath.join(root, folder) : folder;
  return result.replace(rxReplacePath, "/");
};

CSSImage.prototype.name = function(filepath, options) {
  var postfix = options && options.postfix ? options.postfix : "";
  if (options && options.squeeze) { postfix += "-s" + options.squeeze; }
  var prefix = options && (typeof options.prefix !== "undefined") ? options.prefix : "img_";
  var separator = (options && options.separator) || "_";
  var filename = libpath.basename(filepath);
  var ext = libpath.extname(filepath);
  var name = filename.slice(0, filename.length - ext.length).replace(/\./, "");
  var folder = this.normalizeFolder(filepath);
  if (folder === "") { return prefix + name + postfix; }

  // windows fix
  folder = folder.replace(rxReplacePath, separator);
  return prefix + folder + separator + name + postfix;
};

var _cssImage = new CSSImage();
function cssimage(images, _options) {
  var options = _.omit(_options, ["retina", "squeeze"]);
  var isCss = !!options.css;
  var isScss = !!options.scss;
  var root = options.root || "";
  var result = "";
  var isRetina = _options && !!_options.retina;
  var squeeze = (_options && _options.squeeze) || 1;
  for (var i = 0; i < images.length; i++) {
    var img = images[i];
    if (isCss) {
      result += _cssImage.css(img.file, img.width, img.height, root, options);
      if (isRetina) {
        result += _cssImage.css(img.file, img.width, img.height, root, _.extend({
          retina: true
        }, options));
      }
      if (squeeze !== 1) {
        result += _cssImage.css(img.file, img.width, img.height, root, _.extend({
          squeeze: squeeze
        }, options));
      }
    }
    if (isScss) {
      result += _cssImage.scss(img.file, img.width, img.height, root, _.extend({
        retina: isRetina
      }, options));
      if (squeeze !== 1) {
        result += _cssImage.scss(img.file, img.width, img.height, root, _.extend({
          squeeze: squeeze
        }, options));
      }
    }
  }
  return result;
}

module.exports = cssimage;
module.exports.CSSImage = CSSImage;
<|endoftext|>