<commit_before>#!/usr/bin/env node
var argv = require( "minimist" )( process.argv.slice(2) );
var glob = require( "glob" );
var shell = require( "shelljs" );

var GlyphHangerFormat = require( "./src/GlyphHangerFormat" );
var GlyphHangerWhitelist = require( "./src/GlyphHangerWhitelist" );
var PhantomGlyphHanger = require( "./src/PhantomGlyphHanger" );
var PhantomGlyphHangerSpider = require( "./src/PhantomGlyphHangerSpider" );
var GlyphHangerSubset = require( "./src/GlyphHangerSubset" );

var formats = new GlyphHangerFormat( argv.formats );
var whitelist = new GlyphHangerWhitelist( argv.w || argv.whitelist, argv.US_ASCII );

var pgh = new PhantomGlyphHanger();
pgh.setVerbose( argv.verbose );
if( argv.unicodes ) {
	console.log( '--unicodes was made default in v2.0. To output characters instead of code points, use --string' );
	shell.exit(1);
}
pgh.setUnicodesOutput( argv.string );
pgh.setWhitelist( whitelist );
pgh.setSubset( argv.subset );

var subset = new GlyphHangerSubset();
subset.setFormats( formats );

if( argv.subset ) {
	var fontFiles = glob.sync( argv.subset );

	subset.setFontFiles( fontFiles );

	pgh.setFetchUrlsCallback(function( unicodes ) {
		subset.subsetAll( unicodes );
	});
}

if( argv.version ) {
	var pkg = require( "./package.json" );
	console.log( pkg.version );
} else if( ( !argv._ || !argv._.length ) && whitelist.usingWhitelist() ) {
	if( argv.subset ) {
		subset.subsetAll( whitelist.getWhitelistAsUnicodes() );
	} else {
		pgh.output();
	}
} else if( !argv._ || !argv._.length ) {
	pgh.outputHelp();
} else if( argv.spider || argv[ 'spider-limit' ] || argv[ 'spider-limit' ] === 0 ) {
	var spider = new PhantomGlyphHangerSpider();
	spider.setLimit( argv[ 'spider-limit' ] );

	spider.findUrls( argv._, function( urls ) {
		if( argv.verbose ) {
			urls.forEach(function( url, index ) {
				console.log( "glyphhanger-spider found (" + ( index + 1 ) + "): " + url );
			});
		}

		pgh.fetchUrls( urls );
	});
} else {
	pgh.fetchUrls( argv._ );
}
<commit_msg>Shell require<commit_after>#!/usr/bin/env node
var argv = require( "minimist" )( process.argv.slice(2) );
var glob = require( "glob" );
var GlyphHangerFormat = require( "./src/GlyphHangerFormat" );
var GlyphHangerWhitelist = require( "./src/GlyphHangerWhitelist" );
var PhantomGlyphHanger = require( "./src/PhantomGlyphHanger" );
var PhantomGlyphHangerSpider = require( "./src/PhantomGlyphHangerSpider" );
var GlyphHangerSubset = require( "./src/GlyphHangerSubset" );

var formats = new GlyphHangerFormat( argv.formats );
var whitelist = new GlyphHangerWhitelist( argv.w || argv.whitelist, argv.US_ASCII );

var pgh = new PhantomGlyphHanger();
pgh.setVerbose( argv.verbose );
if( argv.unicodes ) {
	console.log( '--unicodes was made default in v2.0. To output characters instead of code points, use --string' );
	require( "shelljs" ).exit(1);
}
pgh.setUnicodesOutput( argv.string );
pgh.setWhitelist( whitelist );
pgh.setSubset( argv.subset );

var subset = new GlyphHangerSubset();
subset.setFormats( formats );

if( argv.subset ) {
	var fontFiles = glob.sync( argv.subset );

	subset.setFontFiles( fontFiles );

	pgh.setFetchUrlsCallback(function( unicodes ) {
		subset.subsetAll( unicodes );
	});
}

if( argv.version ) {
	var pkg = require( "./package.json" );
	console.log( pkg.version );
} else if( ( !argv._ || !argv._.length ) && whitelist.usingWhitelist() ) {
	if( argv.subset ) {
		subset.subsetAll( whitelist.getWhitelistAsUnicodes() );
	} else {
		pgh.output();
	}
} else if( !argv._ || !argv._.length ) {
	pgh.outputHelp();
} else if( argv.spider || argv[ 'spider-limit' ] || argv[ 'spider-limit' ] === 0 ) {
	var spider = new PhantomGlyphHangerSpider();
	spider.setLimit( argv[ 'spider-limit' ] );

	spider.findUrls( argv._, function( urls ) {
		if( argv.verbose ) {
			urls.forEach(function( url, index ) {
				console.log( "glyphhanger-spider found (" + ( index + 1 ) + "): " + url );
			});
		}

		pgh.fetchUrls( urls );
	});
} else {
	pgh.fetchUrls( argv._ );
}
<|endoftext|>


<commit_before>var ProgressBar = require('progress');
var chalk = require('chalk');
var webpack = require('webpack');

require('object.assign').shim();

module.exports = function ProgressBarPlugin(options) {
  options = options || {};

  var stream = options.stream || process.stderr;
  var enabled = stream && stream.isTTY;

  if (!enabled) {
    return function () {};
  }

  var barLeft = chalk.bold('[');
  var barRight = chalk.bold(']');
  var preamble = chalk.cyan.bold('  build ') + barLeft;
  var barFormat = options.format || preamble + ':bar' + barRight + chalk.green.bold(' :percent');
  var summary = options.summary !== false;
  var summaryContent = options.summaryContent;
  var customSummary = options.customSummary;

  delete options.format;
  delete options.total;
  delete options.summary;
  delete options.summaryContent;
  delete options.customSummary;

  var barOptions = Object.assign({
    complete: '=',
    incomplete: ' ',
    width: 20,
    total: 100,
    clear: true
  }, options);

  var bar = new ProgressBar(barFormat, barOptions);

  var running = false;
  var startTime = 0;
  var lastPercent = 0;

  return new webpack.ProgressPlugin(function (percent, msg) {
    if (!running && lastPercent !== 0 && !customSummary) {
      stream.write('\n');
    }

    var newPercent = Math.ceil(percent * barOptions.width);

    if (lastPercent < newPercent || newPercent === 0) {
      bar.update(percent, {
        msg: msg
      });
      lastPercent = newPercent;
    }

    if (!running) {
      running = true;
      startTime = new Date;
      lastPercent = 0;
    } else if (percent === 1) {
      var now = new Date;
      var buildTime = (now - startTime) / 1000 + 's';

      bar.terminate();

      if (summary) {
        stream.write(chalk.green.bold('Build completed in ' + buildTime + '\n\n'));
      } else if (summaryContent) {
        stream.write(summaryContent + '(' + buildTime + ')\n\n');
      }

      if (customSummary) {
        customSummary(buildTime);
      }

      running = false;
    }
  });
};
<commit_msg>Fix #19, thanks to @huruji<commit_after>var ProgressBar = require('progress');
var chalk = require('chalk');
var webpack = require('webpack');

require('object.assign').shim();

module.exports = function ProgressBarPlugin(options) {
  options = options || {};

  var stream = options.stream || process.stderr;
  var enabled = stream && stream.isTTY;

  if (!enabled) {
    return function () {};
  }

  var barLeft = chalk.bold('[');
  var barRight = chalk.bold(']');
  var preamble = chalk.cyan.bold('  build ') + barLeft;
  var barFormat = options.format || preamble + ':bar' + barRight + chalk.green.bold(' :percent');
  var summary = options.summary !== false;
  var summaryContent = options.summaryContent;
  var customSummary = options.customSummary;

  delete options.format;
  delete options.total;
  delete options.summary;
  delete options.summaryContent;
  delete options.customSummary;

  var barOptions = Object.assign({
    complete: '=',
    incomplete: ' ',
    width: 20,
    total: 100,
    clear: true
  }, options);

  var bar = new ProgressBar(barFormat, barOptions);

  var running = false;
  var startTime = 0;
  var lastPercent = 0;

  return new webpack.ProgressPlugin(function (percent) {
    if (!running && lastPercent !== 0 && !customSummary) {
      stream.write('\n');
    }

    var newPercent = Math.floor(percent * barOptions.width);

    if (lastPercent < newPercent || newPercent === 0) {
      bar.update(percent);
      lastPercent = newPercent;
    }

    if (!running) {
      running = true;
      startTime = new Date;
      lastPercent = 0;
    } else if (percent === 1) {
      var now = new Date;
      var buildTime = (now - startTime) / 1000 + 's';

      bar.terminate();

      if (summary) {
        stream.write(chalk.green.bold('Build completed in ' + buildTime + '\n\n'));
      } else if (summaryContent) {
        stream.write(summaryContent + '(' + buildTime + ')\n\n');
      }

      if (customSummary) {
        customSummary(buildTime);
      }

      running = false;
    }
  });
};
<|endoftext|>


<commit_before>/* eslint-disable */
var http = require('http')
var fs = require('fs');
var createHandler = require('travisci-webhook-handler')
var fetch = require('node-fetch')
var request = require('request');

var handler

var conf = JSON.parse(fs.readFileSync(__dirname + '/config.json', 'utf8'));

function sendToTelegram(message) {
  var url = "https://api.telegram.org/bot"+conf.botToken+"/sendMessage"
  request.post(
    url,
    { json: {
      chat_id: conf.chatId,
      text: message,
      parse_mode: "Markdown",
      disable_web_page_preview: true
    } },
    function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body)
        }
    })
  };

if (conf.isKanna) {
  sendToTelegram("Ravioli Ravioli start the Traviswebhookioli")
} else {
  sendToTelegram("Running Travis webhook on `" + conf.path + "`")
}

fetch('https://api.travis-ci.org/config')
  .then((res) => res.text())
  .then(function(body) {
    console.log(JSON.parse(body).config.notifications.webhook.public_key);
    handler = createHandler({
      path: conf.path,
      public_key: JSON.parse(body).config.notifications.webhook.public_key
    })
    http.createServer(function (req, res) {
      handler(req, res, function (err) {
        res.statusCode = 404
        res.end('no such location')
      })
    }).listen(3000)

    handler.on('error', function (err) {
      console.error('Error:', err.message)
      sendToTelegram('Error:\n`'+ err.message+'`')
    })

    handler.on('success', function (event) {
      console.log('Build %s success for %s branch %s',
        event.payload.number,
        event.payload.repository.name,
        event.payload.branch)
      sendToTelegram("*PASSED:*\n"+"Build `"+event.payload.number+"` for `"+event.payload.repository.name+"` on branch `"+event.payload.branch+"`")
    })

    handler.on('failure', function (event) {
        console.log('Build failed!')
        sendToTelegram("*FAILED:*\n"+"Build `"+event.payload.number+"` for `"+event.payload.repository.name+"` on branch `"+event.payload.branch+"`")
    })

    handler.on('start', function (event) {
        console.log('Build started!')
        sendToTelegram("*STARTED:*\n"+"Build `"+event.payload.number+"` for `"+event.payload.repository.name+"` on branch `"+event.payload.branch+"`")
    })

    handler.on('cancel', function (event) {
        console.log('Build cancelled!')
        sendToTelegram("*CANCELLED:*\n"+"Build `"+event.payload.number+"` for `"+event.payload.repository.name+"` on branch `"+event.payload.branch+"`")
    })
  })
<commit_msg>Quick test if using a wildcard is a better option<commit_after>/* eslint-disable */
var http = require('http')
var fs = require('fs');
var createHandler = require('travisci-webhook-handler')
var fetch = require('node-fetch')
var request = require('request');

var handler

var conf = JSON.parse(fs.readFileSync(__dirname + '/config.json', 'utf8'));

function sendToTelegram(message) {
  var url = "https://api.telegram.org/bot"+conf.botToken+"/sendMessage"
  request.post(
    url,
    { json: {
      chat_id: conf.chatId,
      text: message,
      parse_mode: "Markdown",
      disable_web_page_preview: true
    } },
    function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body)
        }
    })
  };

if (conf.isKanna) {
  sendToTelegram("Ravioli Ravioli start the Traviswebhookioli")
} else {
  sendToTelegram("Running Travis webhook on `" + conf.path + "`")
}

fetch('https://api.travis-ci.org/config')
  .then((res) => res.text())
  .then(function(body) {
    console.log(JSON.parse(body).config.notifications.webhook.public_key);
    handler = createHandler({
      path: conf.path,
      public_key: JSON.parse(body).config.notifications.webhook.public_key
    })
    http.createServer(function (req, res) {
      handler(req, res, function (err) {
        res.statusCode = 404
        res.end('no such location')
      })
    }).listen(3000)

    handler.on('*', function (event) {
        sendToTelegram("*"+event.payload.status_message+":*\n"+"Build `"+event.payload.number+"` for `"+event.payload.repository.name+"` on branch `"+event.payload.branch+"`")
    })
  })
<|endoftext|>


<commit_before>'use strict';
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/;

function camelize(string) {
    return string.toLowerCase().replace(/-(.)/g, function (match, group1) {
        return group1.toUpperCase();
    });
}

// Inspired by jQuery. See https://github.com/jquery/jquery/blob/master/src/data.js
function getValue(value) {
    var data   = value,
        result = value;

    if (typeof data === 'string') {
        try {
            if (!data || data === 'true') {
                result = true;
            } else if (data === 'false') {
                result = false;
            } else if (data === 'null') {
                result = null;
            } else if (+data + '' === data) {
                result = +data;
            } else {
                result = rbrace.test(data) ? JSON.parse(data) : data;
            }
        } catch (error) {
        }
    }
    return result;
}

function parseAttrs(gremlin) {
    var el         = gremlin.el;
    var attributes = el.attributes;
    var dataHash   = {};
    var propsHash  = {};

    if (attributes !== null && attributes !== undefined) {
        for (let i = 0; i < attributes.length; i++) {
            var attr = attributes[i];

            if (attr.name.substr(0, 5) !== 'data-') {
                propsHash[camelize(attr.name)] = getValue(attr.value);
            } else {
                dataHash[camelize(attr.name.substr(5))] = getValue(attr.value);
            }
        }

    }
    gremlin.data = dataHash;
    gremlin.props = propsHash;
}

module.exports = {
    initialize() {
        parseAttrs(this);
    }
};
<commit_msg>updating props/data on change<commit_after>'use strict';
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/;

function camelize(string) {
    return string.toLowerCase().replace(/-(.)/g, function (match, group1) {
        return group1.toUpperCase();
    });
}

function isDataAttribute(name) {
    return name.substr(0, 5) === 'data-';
}

// Inspired by jQuery. See https://github.com/jquery/jquery/blob/master/src/data.js
function getValue(value) {
    var data   = value,
        result = value;

    if (typeof data === 'string') {
        try {
            if (!data || data === 'true') {
                result = true;
            } else if (data === 'false') {
                result = false;
            } else if (data === 'null') {
                result = null;
            } else if (+data + '' === data) {
                result = +data;
            } else {
                result = rbrace.test(data) ? JSON.parse(data) : data;
            }
        } catch (error) {
        }
    }
    return result;
}

function parseAttrs(gremlin) {
    var el         = gremlin.el;
    var attributes = el.attributes;
    var dataHash   = {};
    var propsHash  = {};

    if (attributes !== null && attributes !== undefined) {
        for (let i = 0; i < attributes.length; i++) {
            var attr = attributes[i];

            if (isDataAttribute(attr.name)) {
                dataHash[camelize(attr.name.substr(5))] = getValue(attr.value);
            } else {
                propsHash[camelize(attr.name)] = getValue(attr.value);
            }
        }

    }
    gremlin.data = dataHash;
    gremlin.props = propsHash;
}

module.exports = {
    __didInitializeAttributes: false,
    initialize() {
        parseAttrs(this);
        this.__didInitializeAttributes = true;
    },
    attributeDidChange(name, previousValue, value){
        if (this.__didInitializeAttributes) {
            let val = getValue(value);
            if (isDataAttribute(name)) {
                this.data[camelize(name.substr(5))] = val;
            } else {
                this.props[camelize(name)] = val;
            }
        }
    }
};
<|endoftext|>


<commit_before>"use strict";
var DEFAULT_RETRY_MS = 2000;
var Promise = require("bluebird"),
  EventEmitter = require("events"),
  util = require("util"),
  redis = require("redis");

function serialize(value) {
  if (value === null) {
    return "null";
  }

  if (value === undefined) {
    return "undefined";
  }

  return JSON.stringify(value);
}

function deserialize(value) {
  if (value === "null") {
    return null;
  }

  if (value === "undefined") {
    return undefined;
  }

  return JSON.parse(value);
}

function deserializeAll(values) {
  return values.map(deserialize);
}

function RedisCache(options) {
  options = options || {};
  EventEmitter.call(this);

  var self = this;
  options.retry_strategy = options.retry_strategy || function () { return DEFAULT_RETRY_MS; };
  this.poolResolveTimeMs = (options && options.poolTime) || 20;
  this.resolveGetPoolTimer = false;
  this.getPool = [];
  this.client = redis.createClient(options);
  this.client.on("error", function (err) {
    self.emit("error", err);
  });

  this.client.getAsync = Promise.promisify(this.client.get);
  this.client.getAllAsync = Promise.promisify(this.client.mget);
  this.client.setexAsync = Promise.promisify(this.client.setex);
  this.client.setAsync = Promise.promisify(this.client.set);
  this.client.delAsync = Promise.promisify(this.client.del);
  this.client.keysAsync = Promise.promisify(this.client.keys);

  this.get = function (key) {
    return self.addGetToPool(key);
  };

  this.addGetToPool = function (key) {
    return new Promise(function(resolve, reject){
      const getVO = {
        key: key,
        resolve: resolve,
        reject: reject
      };
      self.getPool.push(getVO);
      if(!self.resolveGetPoolTimer) {
        //clearTimeout(self.resolveGetPoolTimer);
        self.resolveGetPoolTimer = setTimeout(self.resolveGetPool, self.poolResolveTimeMs);
      }
    });
  };

  this.resolveGetPool = function () {
    self.resolveGetPoolTimer = false;
    var localGetPool = self.getPool.slice(0);
    self.getPool = [];
    var keys = localGetPool.map(function (getVO) {
      return getVO.key;
    });
    self.getAll(keys)
      .then(function (serializedItems) {
        localGetPool.forEach(function (getVO, index) {
          getVO.resolve(serializedItems[index]);
        });
      })
      .catch(function (err) {
        localGetPool.forEach(function (getVO) {
          getVO.reject(err);
        });
      });

  };

  this.getAll = function (keys) {
    return this.client.getAllAsync(keys).then(deserializeAll);
  };
  this.peek = function (key) {
    return this.get(key);
  };
  this.has = function (key) {
    return this.client.getAsync(key).then(function (value) {
      return value !== null;
    });
  };
  this.set = function (key, value, maxAge) {
    var hasTtl = (typeof maxAge === "number");
    if (hasTtl && maxAge <= 0) {
      return Promise.resolve();
    } else if (hasTtl && maxAge > 0) {
      return this.client.setexAsync(key, Math.round(maxAge / 1000), serialize(value));
    } else if (options && options.maxAge !== undefined){
      return this.set(key, value, options.maxAge);
    } else {
      return this.client.setAsync(key, serialize(value));
    }
  };
  this.del = function (key) {
    return this.client.delAsync(key);
  };
  this.reset = function () {
    return this.client.keysAsync("*").then(function (keys) {
      return Promise.map(keys, function (key) {
        return self.del(key);
      });
    });
  };
}

util.inherits(RedisCache, EventEmitter);

module.exports = RedisCache;
<commit_msg>Add logging on resolve pool<commit_after>"use strict";
var DEFAULT_RETRY_MS = 2000;
var Promise = require("bluebird"),
  EventEmitter = require("events"),
  util = require("util"),
  redis = require("redis");

function serialize(value) {
  if (value === null) {
    return "null";
  }

  if (value === undefined) {
    return "undefined";
  }

  return JSON.stringify(value);
}

function deserialize(value) {
  if (value === "null") {
    return null;
  }

  if (value === "undefined") {
    return undefined;
  }

  return JSON.parse(value);
}

function deserializeAll(values) {
  return values.map(deserialize);
}

function RedisCache(options) {
  options = options || {};
  EventEmitter.call(this);

  var self = this;
  options.retry_strategy = options.retry_strategy || function () { return DEFAULT_RETRY_MS; };
  this.poolResolveTimeMs = (options && options.poolTime) || 20;
  this.resolveGetPoolTimer = false;
  this.getPool = [];
  this.client = redis.createClient(options);
  this.client.on("error", function (err) {
    self.emit("error", err);
  });

  this.client.getAsync = Promise.promisify(this.client.get);
  this.client.getAllAsync = Promise.promisify(this.client.mget);
  this.client.setexAsync = Promise.promisify(this.client.setex);
  this.client.setAsync = Promise.promisify(this.client.set);
  this.client.delAsync = Promise.promisify(this.client.del);
  this.client.keysAsync = Promise.promisify(this.client.keys);

  this.get = function (key) {
    return self.addGetToPool(key);
  };

  this.addGetToPool = function (key) {
    return new Promise(function(resolve, reject){
      const getVO = {
        key: key,
        resolve: resolve,
        reject: reject
      };
      self.getPool.push(getVO);
      if(!self.resolveGetPoolTimer) {
        //clearTimeout(self.resolveGetPoolTimer);
        self.resolveGetPoolTimer = setTimeout(self.resolveGetPool, self.poolResolveTimeMs);
      }
    });
  };

  this.resolveGetPool = function () {
    console.log("Resolving get Pool with size", self.getPool && self.getPool.length);
    self.resolveGetPoolTimer = false;
    var localGetPool = self.getPool.slice(0);
    self.getPool = [];
    var keys = localGetPool.map(function (getVO) {
      return getVO.key;
    });
    self.getAll(keys)
      .then(function (serializedItems) {
        localGetPool.forEach(function (getVO, index) {
          getVO.resolve(serializedItems[index]);
        });
      })
      .catch(function (err) {
        localGetPool.forEach(function (getVO) {
          getVO.reject(err);
        });
      });

  };

  this.getAll = function (keys) {
    return this.client.getAllAsync(keys).then(deserializeAll);
  };
  this.peek = function (key) {
    return this.get(key);
  };
  this.has = function (key) {
    return this.client.getAsync(key).then(function (value) {
      return value !== null;
    });
  };
  this.set = function (key, value, maxAge) {
    var hasTtl = (typeof maxAge === "number");
    if (hasTtl && maxAge <= 0) {
      return Promise.resolve();
    } else if (hasTtl && maxAge > 0) {
      return this.client.setexAsync(key, Math.round(maxAge / 1000), serialize(value));
    } else if (options && options.maxAge !== undefined){
      return this.set(key, value, options.maxAge);
    } else {
      return this.client.setAsync(key, serialize(value));
    }
  };
  this.del = function (key) {
    return this.client.delAsync(key);
  };
  this.reset = function () {
    return this.client.keysAsync("*").then(function (keys) {
      return Promise.map(keys, function (key) {
        return self.del(key);
      });
    });
  };
}

util.inherits(RedisCache, EventEmitter);

module.exports = RedisCache;
<|endoftext|>


<commit_before>'use strict';

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

var _ = require('lodash');
var through = require('through2');
var gutil = require('gulp-util');
var dateformat = require('dateformat');
var url = require('url');
var crypto = require('crypto');

var regOption = 'ig';
var absoluteSrcReg = new RegExp('^\\/{1}[^\\/]+', regOption);
var netSrcReg = new RegExp('.*(\\/\\/).*', regOption);

var fileRevCache = {};

module.exports = handlerFactory;

handlerFactory.createDefaultOptions = createDefaultOptions;

return void(0);

function handlerFactory(options) {

    var defaultOptions = createDefaultOptions();
    var options = _.assign({}, defaultOptions, options);

    var plugin = through.obj(revHandler);

    return plugin;

    // return void(0);

    function revHandler(file, enc, cb) {
        var baseDir = options.base || file.cwd;

        if (options.cwd !== '') {
            var msg = gutil.colors.red('options.cwd is obsoleted, use options.base or set gulp.src(path, {cwd:mycwd}) instead');
            gutil.log(msg);
            return;
        }

        logStart(file);

        if (file.isStream()) {
            var err = new gutil.PluginError('gulp-rev-orig', 'Streaming is not supported');
            this.emit('error', err);
            return cb();
        }

        try {
            if (!file.isNull()) {
                rev(file);
            }
        } catch (err) {
            this.emit('error', new gutil.PluginError('gulp-rev-orig', err));
        }

        logEnd(file);
        this.push(file);
        return cb();

        // return void(0);

        function rev(file) {
            var html = file.contents.toString();

            prepareRegs();

            forEachElementSettings(function(elementSetting) {
                html = addRevsByType(html, elementSetting);
            });

            file.contents = new Buffer(html);

            return void(0);

            function addRevsByType(html, elementSetting) {
                var htmlSegments = html.split(elementSetting.tagReg);
                _.forEach(htmlSegments, function(segment, index, segments) {
                    if (isOdd(index)) {
                        segments[index] = addElementRev(segment, elementSetting);
                    }
                });

                return htmlSegments.join('');
            }

            function prepareRegs() {
                forEachElementSettings(function(elementSetting) {
                    elementSetting.tagReg = new RegExp(elementSetting.tagRegStr, regOption);
                    elementSetting.pathReg = new RegExp(elementSetting.pathRegStr, regOption);
                });
            }

            function forEachElementSettings(cb) {
                _.forEach(options.fileTypes, function(fileType) {
                    return cb(options.elementAttributes[fileType])
                });
            }

            function isOdd(n) {
                return n % 2 === 1;
            }

            function addElementRev(segment, elementSetting) {
                var doAddElementRev = elementSetting.addElementRev || options.defaultAddElementRev;
                return doAddElementRev(segment, addSrcRev, elementSetting);
            }

            function addSrcRev(src) {
                if (src && !netSrcReg.test(src)) {
                    var filePath = getFilePath(src);
                    if (fs.existsSync(filePath)) {
                        var fileRev = getFileRev(filePath);
                        return options.transformPath(src, fileRev);
                    } else {
                        gutil.log(gutil.colors.red(filePath + ' not found'));
                        return src;
                    }
                } else {
                    return src;
                }
            }

            function getFilePath(src) {
                var srcPath = url.parse(src).pathname;
                return absoluteSrcReg.test(srcPath) ?
                    path.join(baseDir, srcPath) :
                    path.join(path.dirname(file.path), srcPath);
            }

            function getFileRev(filePath) {
                if (options.revType === 'hash') {
                    return getFileHashRev(filePath);
                } else {
                    return getFileMtimeRev(filePath);
                }
            }

            function getFileHashRev(filePath) {
                var mtime = getFileMtime(filePath);
                var cacheInfo = fileRevCache[filePath];
                if (cacheInfo && cacheInfo.mtime === mtime) {
                    var msg = gutil.colors.green('found in cache >>' + filePath + '@' + mtime);
                    gutil.log(msg);
                } else {
                    var rev = doGetFileRev(filePath);
                    cacheInfo = fileRevCache[filePath] = {
                        rev: rev,
                        mtime: mtime
                    };
                }
                return cacheInfo.rev;
            }

            function getFileMtimeRev(filePath) {
                return dateformat(new Date(), options.dateFormat);
            }

            function getFileMtime(filePath) {
                return fs.statSync(filePath).mtime;
            }

            function doGetFileRev(filePath) {
                return crypto
                    .createHash('md5')
                    .update(
                        fs.readFileSync(filePath, {
                            encoding: 'utf8'
                        }))
                    .digest('hex')
                    .substring(0, options.hashLength);
            }

        }

        function logStart(file) {
            gutil.log('==== begin rev:', gutil.colors.cyan(file.path));
        }

        function logEnd(file) {
            gutil.log('==== end rev:' + gutil.colors.cyan(file.path));
        }
    }

}

function createDefaultOptions() {
    return {
        cwd: '',
        base: '',
        suffix: 'v',
        fileTypes: ['js', 'css', 'img'],
        hashLength: 8,
        dateFormat: 'yyyymmddHHMM',
        revType: 'hash', // ['hash'|'date']
        transformPath: defaultPathTransformer,
        elementAttributes: getDefaultElementAttributes(),
        defaultAddElementRev: defaultAddElementRev
    };

    // return void(0);

    function defaultAddElementRev(segment, addSrcRev, elementSetting) {
        elementSetting.pathReg.lastIndex = 0;
        var match = elementSetting.pathReg.exec(segment);
        if (match) {
            var src = match[2];
            var revSrc = addSrcRev(src);
            return segment.replace(elementSetting.pathReg, '$1' + revSrc + '$3');
        } else {
            return segment;
        }
    }

    function defaultPathTransformer(orgPath, rev) {
        var regStr = '((\\?|\\&|\\&amp\\;)' + this.suffix + '=)([^&\\s]+)';
        var reg = new RegExp(regStr, regOption);
        var newpath = orgPath;
        if (reg.test(orgPath)) {
            newpath = orgPath.replace(reg, '$1' + rev);
        } else {
            newpath += ((orgPath.indexOf('?') > -1 ? '&' : '?') + this.suffix + '=' + rev);
        }
        return newpath;
    }

    function getDefaultElementAttributes() {
        return {
            js: {
                tagRegStr: '(<script [^>]+/?>)',
                pathRegStr: '(?:(\\s+src=")([^"]+)("))'
            },
            css: {
                tagRegStr: '(<link [^>]+/?>)',
                pathRegStr: '(?:(\\s+href=")([^"]+)("))'
            },
            img: {
                tagRegStr: '(<img [^>]+/?>)',
                pathRegStr: '(?:(\\s+src=")([^"]+)("))'
            }
        };
    }
}<commit_msg>remove reg option -g<commit_after>'use strict';

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

var _ = require('lodash');
var through = require('through2');
var gutil = require('gulp-util');
var dateformat = require('dateformat');
var url = require('url');
var crypto = require('crypto');

var regOption = 'i';
var absoluteSrcReg = new RegExp('^\\/{1}[^\\/]+', regOption);
var netSrcReg = new RegExp('.*(\\/\\/).*', regOption);

var fileRevCache = {};

module.exports = handlerFactory;

handlerFactory.createDefaultOptions = createDefaultOptions;

return void(0);

function handlerFactory(options) {

	var defaultOptions = createDefaultOptions();
	var options = _.assign({}, defaultOptions, options);

	var plugin = through.obj(revHandler);

	return plugin;

	// return void(0);

	function revHandler(file, enc, cb) {
		var baseDir = options.base || file.cwd;

		if(options.cwd !== '') {
			var msg = gutil.colors.red('options.cwd is obsoleted, use options.base or set gulp.src(path, {cwd:mycwd}) instead');
			gutil.log(msg);
			return;
		}

		logStart(file);

		if(file.isStream()) {
			var err = new gutil.PluginError('gulp-rev-orig', 'Streaming is not supported');
			this.emit('error', err);
			return cb();
		}

		try {
			if(!file.isNull()) {
				rev(file);
			}
		} catch(err) {
			this.emit('error', new gutil.PluginError('gulp-rev-orig', err));
		}

		logEnd(file);
		this.push(file);
		return cb();

		// return void(0);

		function rev(file) {
			var html = file.contents.toString();

			prepareRegs();

			forEachElementSettings(function (elementSetting) {
				html = addRevsByType(html, elementSetting);
			});

			file.contents = new Buffer(html);

			return void(0);

			function addRevsByType(html, elementSetting) {
				var htmlSegments = html.split(elementSetting.tagReg);
				_.forEach(htmlSegments, function (segment, index, segments) {
					if(isOdd(index)) {
						segments[index] = addElementRev(segment, elementSetting);
					}
				});

				return htmlSegments.join('');
			}

			function prepareRegs() {
				forEachElementSettings(function (elementSetting) {
					elementSetting.tagReg = new RegExp(elementSetting.tagRegStr, regOption);
					elementSetting.pathReg = new RegExp(elementSetting.pathRegStr, regOption);
				});
			}

			function forEachElementSettings(cb) {
				_.forEach(options.fileTypes, function (fileType) {
					return cb(options.elementAttributes[fileType])
				});
			}

			function isOdd(n) {
				return n % 2 === 1;
			}

			function addElementRev(segment, elementSetting) {
				var doAddElementRev = elementSetting.addElementRev || options.defaultAddElementRev;
				return doAddElementRev(segment, addSrcRev, elementSetting);
			}

			function addSrcRev(src) {
				if(src && !netSrcReg.test(src)) {
					var filePath = getFilePath(src);
					if(fs.existsSync(filePath)) {
						var fileRev = getFileRev(filePath);
						return options.transformPath(src, fileRev);
					} else {
						gutil.log(gutil.colors.red(filePath + ' not found'));
						return src;
					}
				} else {
					return src;
				}
			}

			function getFilePath(src) {
				var srcPath = url.parse(src)
					.pathname;
				return absoluteSrcReg.test(srcPath) ?
					path.join(baseDir, srcPath) :
					path.join(path.dirname(file.path), srcPath);
			}

			function getFileRev(filePath) {
				if(options.revType === 'hash') {
					return getFileHashRev(filePath);
				} else {
					return getFileMtimeRev(filePath);
				}
			}

			function getFileHashRev(filePath) {
				var mtime = getFileMtime(filePath);
				var cacheInfo = fileRevCache[filePath];
				if(cacheInfo && cacheInfo.mtime === mtime) {
					var msg = gutil.colors.green('found in cache >>' + filePath + '@' + mtime);
					gutil.log(msg);
				} else {
					var rev = doGetFileRev(filePath);
					cacheInfo = fileRevCache[filePath] = {
						rev: rev,
						mtime: mtime
					};
				}
				return cacheInfo.rev;
			}

			function getFileMtimeRev(filePath) {
				return dateformat(new Date(), options.dateFormat);
			}

			function getFileMtime(filePath) {
				return fs.statSync(filePath)
					.mtime;
			}

			function doGetFileRev(filePath) {
				return crypto
					.createHash('md5')
					.update(
						fs.readFileSync(filePath, {
							encoding: 'utf8'
						}))
					.digest('hex')
					.substring(0, options.hashLength);
			}

		}

		function logStart(file) {
			gutil.log('==== begin rev:', gutil.colors.cyan(file.path));
		}

		function logEnd(file) {
			gutil.log('==== end rev:' + gutil.colors.cyan(file.path));
		}
	}

}

function createDefaultOptions() {
	return {
		cwd: '',
		base: '',
		suffix: 'v',
		fileTypes: ['js', 'css', 'img'],
		hashLength: 8,
		dateFormat: 'yyyymmddHHMM',
		revType: 'hash', // ['hash'|'date']
		transformPath: defaultPathTransformer,
		elementAttributes: getDefaultElementAttributes(),
		defaultAddElementRev: defaultAddElementRev
	};

	// return void(0);

	function defaultAddElementRev(segment, addSrcRev, elementSetting) {
		elementSetting.pathReg.lastIndex = 0;
		var match = elementSetting.pathReg.exec(segment);
		if(match) {
			var src = match[2];
			var revSrc = addSrcRev(src);
			return segment.replace(elementSetting.pathReg, '$1' + revSrc + '$3');
		} else {
			return segment;
		}
	}

	function defaultPathTransformer(orgPath, rev) {
		var regStr = '((\\?|\\&|\\&amp\\;)' + this.suffix + '=)([^&\\s]+)';
		var reg = new RegExp(regStr, regOption);
		var newpath = orgPath;
		if(reg.test(orgPath)) {
			newpath = orgPath.replace(reg, '$1' + rev);
		} else {
			newpath += ((orgPath.indexOf('?') > -1 ? '&' : '?') + this.suffix + '=' + rev);
		}
		return newpath;
	}

	function getDefaultElementAttributes() {
		return {
			js: {
				tagRegStr: '(<script [^>]+/?>)',
				pathRegStr: '(?:(\\s+src=")([^"]+)("))'
			},
			css: {
				tagRegStr: '(<link [^>]+/?>)',
				pathRegStr: '(?:(\\s+href=")([^"]+)("))'
			},
			img: {
				tagRegStr: '(<img [^>]+/?>)',
				pathRegStr: '(?:(\\s+src=")([^"]+)("))'
			}
		};
	}
}
<|endoftext|>


<commit_before>/**
 *  class Wire
 **/
'use strict';

var nextTick = require('next-tick');

//////////////////////////////////////////////////////////////////////////////
// Helpers

function _class(obj) { return Object.prototype.toString.call(obj); }

function isString(obj) { return _class(obj) === '[object String]'; }
function isFunction(obj) { return _class(obj) === '[object Function]'; }

//
// Simplified stable sort implementation from Lo-Dash (http://lodash.com/)
//

function compareAscending(a, b) {
  var ai = a.idx,
      bi = b.idx;

  a = a.criteria;
  b = b.criteria;

  // ensure a stable sort in V8 and other engines
  // http://code.google.com/p/v8/issues/detail?id=90
  if (a !== b) {
    if (a > b || typeof a === 'undefined') {
      return 1;
    }
    /*istanbul ignore next*/
    if (a < b || typeof b === 'undefined') {
      return -1;
    }
  }

  /*istanbul ignore next*/
  return ai < bi ? -1 : 1;
}

function stableSort(arr) {
  var idx,
      len    = arr.length,
      result = new Array(len);

  for (idx = 0; idx < len; idx += 1) {
    result[idx] = {
      criteria: arr[idx].priority,
      idx:      idx,
      val:      arr[idx]
    };
  }

  result.sort(compareAscending);

  for (idx = 0; idx < len; idx += 1) {
    result[idx] = result[idx].val;
  }

  return result;
}

function isGeneratorFunction(obj) {
  var constructor = obj.constructor;
  /*istanbul ignore if*/
  if (!constructor) {
    return false;
  }
  if (constructor.name === 'GeneratorFunction' ||
      constructor.displayName === 'GeneratorFunction') {
    return true;
  }
  return false;
}

function isPromise(obj) {
  return typeof obj.then === 'function';
}

//////////////////////////////////////////////////////////////////////////////

// Structure to hold handler data
function WireHandler(channel, options, func) {
  if (channel.indexOf('*') !== -1 &&
      channel.indexOf('*') !== channel.length - 1) {
    throw new Error("Bad channel name '" + channel + "'. Broadcast symbol (*) must " +
                    'be the last character.');
  }

  this.channel   = channel;
  this.func      = func;
  this.name      = func.name || options.name || '<anonymous>';
  this.gen       = isGeneratorFunction(func);
  this.sync      = func.length === 0 || func.length === 1;
  this.once      = Boolean(options.once);
  this.ensure    = Boolean(options.ensure);
  this.priority  = Number(options.priority || 0);
  this.ncalled   = 0;

  // Use channel name of this handler only as a prefix to match or not.
  this.isBroadcast = (channel.charAt(channel.length - 1) === '*');

  // Used to match this handler.
  this.lookupString = this.isBroadcast ? channel.slice(0, -1) : channel;
}

//////////////////////////////////////////////////////////////////////////////

function Wire(options) {
  if (!(this instanceof Wire)) { return new Wire(options); }

  var opts = options || {};

  this.__co = opts.co || require('co');
  this.__p = opts.p || Promise;

  this.__hooks          = {};
  this.__handlers       = [];
  this.__sortedCache    = [];
  this.__knownChannels  = {};
  this.__skips          = {};
}

// Add hook.
//
Wire.prototype.hook = function (eventName, handler) {
  this.__hooks[eventName] = this.__hooks[eventName] || [];
  this.__hooks[eventName].push(handler);
};

// Returns true if `handlerName` must be skipped on `channelName`.
//
Wire.prototype.__checkSkip = function (handlerName, channelName) {

  return !!(this.__skips[handlerName] || []).some(function (skip) {
    var wcard = skip.charAt(skip.length - 1) === '*';

    if (!wcard && skip === channelName) { return true; }

    if (wcard && (channelName.indexOf(skip.slice(0, -1)) === 0)) { return true; }
  });
};

Wire.prototype.__getHandlers = function (channel) {
  var self = this, result;

  if (!this.__sortedCache[channel]) {
    result = [];

    this.__handlers.forEach(function (handler) {

      // Respect skips.
      if (self.__checkSkip(handler.name, channel)) {
        return;
      }

      // Non-broadcast handler - do exact match.
      if (!handler.isBroadcast && (channel !== handler.lookupString)) {
        return;
      }

      // Broadcast handler - match as a prefix.
      if (handler.isBroadcast && (channel.indexOf(handler.lookupString)) !== 0) {
        return;
      }

      result.push(handler);
    });

    // We must use stable sort here to be sure, that handlers in the resulting
    // list will be placed exactly in the order they are declared.
    this.__sortedCache[channel] = stableSort(result);
  }

  return this.__sortedCache[channel];
};

// Helper to run hooks
//
function _hook(slf, name, handlerInfo, params) {
  if (!slf.__hooks[name]) { return; }

  slf.__hooks[name].forEach(function (hook) {
    hook(handlerInfo, params);
  });
}

// Run all listeners for specific channel
//
Wire.prototype.__emitOne = function (ch, params) {
  var p = this.__co.co(true),
      self = this,
      errored = false, err;

  function storeErrOnce(e) {
    if (errored) { return; }
    errored = true;
    err = e;
  }

  this.__getHandlers(ch).slice().forEach(function (wh) {
    var fn = wh.func;

    if (!fn) { return; }

    if (wh.once) { self.off(wh.channel, fn); }

    if (wh.gen) {
      // Handler is generator
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        return self.__co(fn, params);
      });

    } else if (wh.sync) {
      // Handler is sync function, but can
      // throw, return error or Promise.
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        var val = fn(params);

        if (val) {
          if (isPromise(val)) { return val; }
          throw val;
        }
      });
    } else {
      // Handler is async function
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        return new self.__p(function (resolve, reject) {
          fn(params, function (err) {
            if (!err) {
              resolve();
            } else {
              reject (err);
            }
          });
        });
      });
    }

    // Finalize handlker exec - should care about errors and post-hooks.
    p =  p.catch(storeErrOnce)
          .then(function () {
            if (errored && !wh.ensure) { return null; }
            _hook(self, 'eachAfter', wh, params);
          })
          .catch(storeErrOnce);
  });

  // We combined full chain of calls, now restore
  // the first error if happened, and return as promise.
  return p.then(function () {
    if (errored) { throw err; }
  });
};

/**
 *  Wire#emit(channels [, params, callback]) -> Void
 *  - channel (String):
 *  - params (Mixed):
 *  - callback (Function):
 *
 *  Sends message with `params` into the `channel`. Once all sync and ascync
 *  handlers finished, optional `callback(err)` (if specified) fired.
 **/
Wire.prototype.emit = function (channel, params, callback) {
  if (!callback && isFunction(params)) {
    callback = params;
    params = null;
  }

  var p = this.__p.resolve();

  if (!isString(channel)) {
    p = p.then(function () {
      throw new Error('Channel name should be a string: ' + channel);
    });
  }
  if (channel.indexOf('*') >= 0) {
    p = p.then(function () {
      throw new Error("Bad channel name '" + channel + "'. Wildard `*` not allowed in emitter");
    });
  }

  var self = this;
  p = p.then(function () { return self.__emitOne(channel, params); });

  // No callback - return promise
  if (!callback) {
    return p;
  }

  // Callback magic
  p.then(function () {
      nextTick(callback.bind(null));
    })
    .catch(function (err) {
      nextTick(callback.bind(null, err));
    });
};

/**
 *  Wire#on(channels[, options], handler) -> Void
 *  - channels (String | Array):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Registers `handler` to be executed upon messages in the a single channel
 *  or a sequence of channels stored in `channels` parameter. Handler can be
 *  either sync function:
 *
 *      wire.on('foobar', function () {
 *        // do stuff here
 *      });
 *
 *      wire.on('foobar', function (params) {
 *        // do stuff here
 *      });
 *
 *  Or it might be an async function with `callback(err)` second argument:
 *
 *      wire.on('foobar', function (params, callback) {
 *        // do stuff here
 *        callback(null);
 *      });
 *
 *
 *  ##### Options
 *
 *  - `priority` (Number, Default: 0)
 *  - `ensure` (Boolean, Default: false)
 *    If `true`, will run handler even if one of previous fired error.
 **/
Wire.prototype.on = function (channels, options, handler) {
  if (!channels) {
    throw new Error('Channel name required. Use `*` if you want "any channel".');
  }

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

  if (!handler) {
    handler = options;
    options = null;
  }

  options = options || {};

  if (!isFunction(handler)) {
    throw new Error('Listener should be the function');
  }

  if (handler.length !== 0 && handler.length !== 1 && handler.length !== 2) {
    throw new Error('Function must accept exactly 0 (sync), 1 (sync), or 2 (async) arguments');
  }

  channels.forEach(function (channelName) {
    var wh = new WireHandler(channelName, options, handler);

    // Count main channel handler (no wildcards, zero-priority)
    if (wh.priority === 0) {
      this.__knownChannels[channelName] = (this.__knownChannels[channelName] || 0) + 1;
    }

    this.__handlers.push(wh);
  }, this);

  // TODO: Move to separate method
  this.__sortedCache = [];
};

/**
 *  Wire#once(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but runs handler one time only.
 **/
Wire.prototype.once = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.once = true;

  this.on(channel, options, handler);
};

/**
 *  Wire#before(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with 'fixed' priority of `-10`
 **/
Wire.prototype.before = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || -10;

  if (options.priority >= 0) {
    throw new Error('.before() requires priority lower than 0');
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#after(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with default priority of `10`
 **/
Wire.prototype.after = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || 10;

  if (options.priority <= 0) {
    throw new Error('.after() requires priority greater than 0');
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#off(channel[, handler]) -> Void
 *  - channel (String):
 *  - handler (Function):
 *
 *  Removes `handler` of a channel, or removes ALL handlers of a channel if
 *  `handler` is not given.
 **/
Wire.prototype.off = function (channel, handler) {

  this.__handlers.forEach(function (wh) {
    if (channel !== wh.channel) {
      return; // continue
    }

    if (handler && (handler !== wh.func)) {
      return; // continue
    }

    // Uncount back zero-priority handler
    if (wh.priority === 0) {
      this.__knownChannels[channel]--;
    }

    wh.func = null;
  }, this);
};

/**
 *  Wire#skip(channel, skipList) -> Void
 *  - channel (String):
 *  - skipList (Array):
 *
 *  Exclude calling list of named handlers for given chennel:
 *
 *      wire.skip('server:static', [
 *        session_start,
 *        cookies_start
 *      ]);
 *
 **/
Wire.prototype.skip = function (channel, skipList) {

  if (channel.indexOf('*') !== -1 &&
      channel.indexOf('*') !== channel.length - 1) {
    throw new Error("Bad channel name '" + channel + "'. Wildard can be tailing only.");
  }

  if (isString(skipList)) {
    skipList = [ skipList ];
  }

  if (!Array.isArray(skipList)) {
    throw new Error('skipList must be String or Array of Strings');
  }

  this.__skips[channel] = this.__skips[channel] || {};

  skipList.forEach(function (name) {
    if (!this.__skips.hasOwnProperty(name)) {
      this.__skips[name] = [];
    }

    // Add channel name only if it not exists.
    if (this.__skips[name].indexOf(channel) === -1) {
      this.__skips[name].push(channel);
    }
  }, this);

  // TODO: Move to separate method
  this.__sortedCache = [];
};

/**
 *  Wire#has(channel) -> Boolean
 *  - channel (String):
 *
 *  Returns if `channel` has at least one subscriber
 *  with zero priority (main handler)
 **/
Wire.prototype.has = function (channel) {
  return Boolean(this.__knownChannels[channel]);
};

/**
 *  Wire#stat() -> Object
 *
 *  Returns Array of info about every channel. For debug purposes. For example,
 *  you can write dumper to check that all expected channels have required
 *  handlers. Or to track number of calls.
 **/
Wire.prototype.stat = function () {
  var result = [],
      known = [];

  // Scan all unique channels, ignore priorities
  this.__handlers.forEach(function (wh) {
    if (known.indexOf(wh.channel) === -1) {
      known.push(wh.channel);
    }
  });
  known = known.sort();

  // Extract info
  known.forEach(function (name) {
    result.push({ name : name, listeners: this.__getHandlers(name) });
  }, this);

  return result;
};

module.exports = Wire;
<commit_msg>Fixed promise create<commit_after>/**
 *  class Wire
 **/
'use strict';

var nextTick = require('next-tick');

//////////////////////////////////////////////////////////////////////////////
// Helpers

function _class(obj) { return Object.prototype.toString.call(obj); }

function isString(obj) { return _class(obj) === '[object String]'; }
function isFunction(obj) { return _class(obj) === '[object Function]'; }

//
// Simplified stable sort implementation from Lo-Dash (http://lodash.com/)
//

function compareAscending(a, b) {
  var ai = a.idx,
      bi = b.idx;

  a = a.criteria;
  b = b.criteria;

  // ensure a stable sort in V8 and other engines
  // http://code.google.com/p/v8/issues/detail?id=90
  if (a !== b) {
    if (a > b || typeof a === 'undefined') {
      return 1;
    }
    /*istanbul ignore next*/
    if (a < b || typeof b === 'undefined') {
      return -1;
    }
  }

  /*istanbul ignore next*/
  return ai < bi ? -1 : 1;
}

function stableSort(arr) {
  var idx,
      len    = arr.length,
      result = new Array(len);

  for (idx = 0; idx < len; idx += 1) {
    result[idx] = {
      criteria: arr[idx].priority,
      idx:      idx,
      val:      arr[idx]
    };
  }

  result.sort(compareAscending);

  for (idx = 0; idx < len; idx += 1) {
    result[idx] = result[idx].val;
  }

  return result;
}

function isGeneratorFunction(obj) {
  var constructor = obj.constructor;
  /*istanbul ignore if*/
  if (!constructor) {
    return false;
  }
  if (constructor.name === 'GeneratorFunction' ||
      constructor.displayName === 'GeneratorFunction') {
    return true;
  }
  return false;
}

function isPromise(obj) {
  return typeof obj.then === 'function';
}

//////////////////////////////////////////////////////////////////////////////

// Structure to hold handler data
function WireHandler(channel, options, func) {
  if (channel.indexOf('*') !== -1 &&
      channel.indexOf('*') !== channel.length - 1) {
    throw new Error("Bad channel name '" + channel + "'. Broadcast symbol (*) must " +
                    'be the last character.');
  }

  this.channel   = channel;
  this.func      = func;
  this.name      = func.name || options.name || '<anonymous>';
  this.gen       = isGeneratorFunction(func);
  this.sync      = func.length === 0 || func.length === 1;
  this.once      = Boolean(options.once);
  this.ensure    = Boolean(options.ensure);
  this.priority  = Number(options.priority || 0);
  this.ncalled   = 0;

  // Use channel name of this handler only as a prefix to match or not.
  this.isBroadcast = (channel.charAt(channel.length - 1) === '*');

  // Used to match this handler.
  this.lookupString = this.isBroadcast ? channel.slice(0, -1) : channel;
}

//////////////////////////////////////////////////////////////////////////////

function Wire(options) {
  if (!(this instanceof Wire)) { return new Wire(options); }

  var opts = options || {};

  this.__co = opts.co || require('co');
  this.__p = opts.p || Promise;

  this.__hooks          = {};
  this.__handlers       = [];
  this.__sortedCache    = [];
  this.__knownChannels  = {};
  this.__skips          = {};
}

// Add hook.
//
Wire.prototype.hook = function (eventName, handler) {
  this.__hooks[eventName] = this.__hooks[eventName] || [];
  this.__hooks[eventName].push(handler);
};

// Returns true if `handlerName` must be skipped on `channelName`.
//
Wire.prototype.__checkSkip = function (handlerName, channelName) {

  return !!(this.__skips[handlerName] || []).some(function (skip) {
    var wcard = skip.charAt(skip.length - 1) === '*';

    if (!wcard && skip === channelName) { return true; }

    if (wcard && (channelName.indexOf(skip.slice(0, -1)) === 0)) { return true; }
  });
};

Wire.prototype.__getHandlers = function (channel) {
  var self = this, result;

  if (!this.__sortedCache[channel]) {
    result = [];

    this.__handlers.forEach(function (handler) {

      // Respect skips.
      if (self.__checkSkip(handler.name, channel)) {
        return;
      }

      // Non-broadcast handler - do exact match.
      if (!handler.isBroadcast && (channel !== handler.lookupString)) {
        return;
      }

      // Broadcast handler - match as a prefix.
      if (handler.isBroadcast && (channel.indexOf(handler.lookupString)) !== 0) {
        return;
      }

      result.push(handler);
    });

    // We must use stable sort here to be sure, that handlers in the resulting
    // list will be placed exactly in the order they are declared.
    this.__sortedCache[channel] = stableSort(result);
  }

  return this.__sortedCache[channel];
};

// Helper to run hooks
//
function _hook(slf, name, handlerInfo, params) {
  if (!slf.__hooks[name]) { return; }

  slf.__hooks[name].forEach(function (hook) {
    hook(handlerInfo, params);
  });
}

// Run all listeners for specific channel
//
Wire.prototype.__emitOne = function (ch, params) {
  var p = this.__p.resolve(),
      self = this,
      errored = false, err;

  function storeErrOnce(e) {
    if (errored) { return; }
    errored = true;
    err = e;
  }

  this.__getHandlers(ch).slice().forEach(function (wh) {
    var fn = wh.func;

    if (!fn) { return; }

    if (wh.once) { self.off(wh.channel, fn); }

    if (wh.gen) {
      // Handler is generator
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        return self.__co(fn, params);
      });

    } else if (wh.sync) {
      // Handler is sync function, but can
      // throw, return error or Promise.
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        var val = fn(params);

        if (val) {
          if (isPromise(val)) { return val; }
          throw val;
        }
      });
    } else {
      // Handler is async function
      p = p.then(function () {
        if (errored && !wh.ensure) { return null; }
        wh.ncalled++;
        _hook(self, 'eachBefore', wh, params);

        return new self.__p(function (resolve, reject) {
          fn(params, function (err) {
            if (!err) {
              resolve();
            } else {
              reject (err);
            }
          });
        });
      });
    }

    // Finalize handlker exec - should care about errors and post-hooks.
    p =  p.catch(storeErrOnce)
          .then(function () {
            if (errored && !wh.ensure) { return null; }
            _hook(self, 'eachAfter', wh, params);
          })
          .catch(storeErrOnce);
  });

  // We combined full chain of calls, now restore
  // the first error if happened, and return as promise.
  return p.then(function () {
    if (errored) { throw err; }
  });
};

/**
 *  Wire#emit(channels [, params, callback]) -> Void
 *  - channel (String):
 *  - params (Mixed):
 *  - callback (Function):
 *
 *  Sends message with `params` into the `channel`. Once all sync and ascync
 *  handlers finished, optional `callback(err)` (if specified) fired.
 **/
Wire.prototype.emit = function (channel, params, callback) {
  if (!callback && isFunction(params)) {
    callback = params;
    params = null;
  }

  var p = this.__p.resolve();

  if (!isString(channel)) {
    p = p.then(function () {
      throw new Error('Channel name should be a string: ' + channel);
    });
  }
  if (channel.indexOf('*') >= 0) {
    p = p.then(function () {
      throw new Error("Bad channel name '" + channel + "'. Wildard `*` not allowed in emitter");
    });
  }

  var self = this;
  p = p.then(function () { return self.__emitOne(channel, params); });

  // No callback - return promise
  if (!callback) {
    return p;
  }

  // Callback magic
  p.then(function () {
      nextTick(callback.bind(null));
    })
    .catch(function (err) {
      nextTick(callback.bind(null, err));
    });
};

/**
 *  Wire#on(channels[, options], handler) -> Void
 *  - channels (String | Array):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Registers `handler` to be executed upon messages in the a single channel
 *  or a sequence of channels stored in `channels` parameter. Handler can be
 *  either sync function:
 *
 *      wire.on('foobar', function () {
 *        // do stuff here
 *      });
 *
 *      wire.on('foobar', function (params) {
 *        // do stuff here
 *      });
 *
 *  Or it might be an async function with `callback(err)` second argument:
 *
 *      wire.on('foobar', function (params, callback) {
 *        // do stuff here
 *        callback(null);
 *      });
 *
 *
 *  ##### Options
 *
 *  - `priority` (Number, Default: 0)
 *  - `ensure` (Boolean, Default: false)
 *    If `true`, will run handler even if one of previous fired error.
 **/
Wire.prototype.on = function (channels, options, handler) {
  if (!channels) {
    throw new Error('Channel name required. Use `*` if you want "any channel".');
  }

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

  if (!handler) {
    handler = options;
    options = null;
  }

  options = options || {};

  if (!isFunction(handler)) {
    throw new Error('Listener should be the function');
  }

  if (handler.length !== 0 && handler.length !== 1 && handler.length !== 2) {
    throw new Error('Function must accept exactly 0 (sync), 1 (sync), or 2 (async) arguments');
  }

  channels.forEach(function (channelName) {
    var wh = new WireHandler(channelName, options, handler);

    // Count main channel handler (no wildcards, zero-priority)
    if (wh.priority === 0) {
      this.__knownChannels[channelName] = (this.__knownChannels[channelName] || 0) + 1;
    }

    this.__handlers.push(wh);
  }, this);

  // TODO: Move to separate method
  this.__sortedCache = [];
};

/**
 *  Wire#once(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but runs handler one time only.
 **/
Wire.prototype.once = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.once = true;

  this.on(channel, options, handler);
};

/**
 *  Wire#before(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with 'fixed' priority of `-10`
 **/
Wire.prototype.before = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || -10;

  if (options.priority >= 0) {
    throw new Error('.before() requires priority lower than 0');
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#after(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with default priority of `10`
 **/
Wire.prototype.after = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || 10;

  if (options.priority <= 0) {
    throw new Error('.after() requires priority greater than 0');
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#off(channel[, handler]) -> Void
 *  - channel (String):
 *  - handler (Function):
 *
 *  Removes `handler` of a channel, or removes ALL handlers of a channel if
 *  `handler` is not given.
 **/
Wire.prototype.off = function (channel, handler) {

  this.__handlers.forEach(function (wh) {
    if (channel !== wh.channel) {
      return; // continue
    }

    if (handler && (handler !== wh.func)) {
      return; // continue
    }

    // Uncount back zero-priority handler
    if (wh.priority === 0) {
      this.__knownChannels[channel]--;
    }

    wh.func = null;
  }, this);
};

/**
 *  Wire#skip(channel, skipList) -> Void
 *  - channel (String):
 *  - skipList (Array):
 *
 *  Exclude calling list of named handlers for given chennel:
 *
 *      wire.skip('server:static', [
 *        session_start,
 *        cookies_start
 *      ]);
 *
 **/
Wire.prototype.skip = function (channel, skipList) {

  if (channel.indexOf('*') !== -1 &&
      channel.indexOf('*') !== channel.length - 1) {
    throw new Error("Bad channel name '" + channel + "'. Wildard can be tailing only.");
  }

  if (isString(skipList)) {
    skipList = [ skipList ];
  }

  if (!Array.isArray(skipList)) {
    throw new Error('skipList must be String or Array of Strings');
  }

  this.__skips[channel] = this.__skips[channel] || {};

  skipList.forEach(function (name) {
    if (!this.__skips.hasOwnProperty(name)) {
      this.__skips[name] = [];
    }

    // Add channel name only if it not exists.
    if (this.__skips[name].indexOf(channel) === -1) {
      this.__skips[name].push(channel);
    }
  }, this);

  // TODO: Move to separate method
  this.__sortedCache = [];
};

/**
 *  Wire#has(channel) -> Boolean
 *  - channel (String):
 *
 *  Returns if `channel` has at least one subscriber
 *  with zero priority (main handler)
 **/
Wire.prototype.has = function (channel) {
  return Boolean(this.__knownChannels[channel]);
};

/**
 *  Wire#stat() -> Object
 *
 *  Returns Array of info about every channel. For debug purposes. For example,
 *  you can write dumper to check that all expected channels have required
 *  handlers. Or to track number of calls.
 **/
Wire.prototype.stat = function () {
  var result = [],
      known = [];

  // Scan all unique channels, ignore priorities
  this.__handlers.forEach(function (wh) {
    if (known.indexOf(wh.channel) === -1) {
      known.push(wh.channel);
    }
  });
  known = known.sort();

  // Extract info
  known.forEach(function (name) {
    result.push({ name : name, listeners: this.__getHandlers(name) });
  }, this);

  return result;
};

module.exports = Wire;
<|endoftext|>


<commit_before>#! /usr/bin/env node

var fs = require('fs');
var exec = require('child_process').exec;
var prompt = require("prompt");
var program = require('commander');
var _ = require('underscore');
var async = require('async');

var packageInfo = require('./package.json');
var licenseTpls = require('./lib/license_tpl.json');
var args = process.argv.slice(2);

var config = {};
// handle th cmd-line logical and parse options.
if(args.length <= 0) {
    doAsk();
} else if(args.join('').indexOf('-') < 0 && args.indexOf('version') < 0) {
    async.waterfall([
        function(callback) {
            doMatch(function(err, result) {
                if(err) console.log(err.msg);
                callback(null, result);
            })
        },
        function(licenseType, callback) {
            getBasicInfo(function(err, result) {
                callback(null, licenseType, result);
            })
        },
        function(licenseType, config, callback) {
            genLice(licenseType, config, function(err, result) {
                if(err) console.error(err);
                console.log('LICENSE has been generated!');
            })
        }
    ]);
} else {
    getBasicInfo();
}

function getBasicInfo(callback) {
    async.waterfall([
        function(callback) {
            program
                .description('Use this command to generate a license file.')
                .version(packageInfo.version)
                .option('-a, --author <author>', 'Your name.', packageInfo.author)
                .option('-y, --year <year>', 'Year used in your license.', new Date().getFullYear())
                .option('-p, --project <project>', 'Project\'s name', packageInfo.name)
                .parse(process.argv);

            config = {
                author: program.author,
                year: program.year,
                project: program.project
            };

            callback(null, config);
        },
        function(config, callback) {

            // if no project name in package.json, use dir name insteed.
            if(!config.project) {
                config.project = __dirname.split('/').pop();
            }

            // if neither [-a] arg provided nor author info in package.json, use git config insteed.
            // TODO, if none of these specify an author name.
            if(!config.author) {
                exec('git config --get user.name', function(err, stdout, stderr) {
                    if(err) throw err;
                    config.author = stdout.replace(/[\n\r]/g, '');
                    callback(null, config);
                })
            } else {
                callback(null, config);
            }
        }
    ], function(err, result) {
        callback(err, result);
    });
}

function doAsk(callback) {
    prompt.message = "license-gen!".cyan;
    prompt.delimiter = " ".green;
    prompt.start();

    prompt.get({
        properties: {
            author: {
                description: "Input your name.",
                message: 'You must specify your name',
                required: true
            },
            year: {
                type: 'number',
                description: "Input the year to used inyour license.",
                message: "You should input a number or leave blank to use current year.",
                default: new Date().getFullYear()
            },
            project: {
                description: "Input the project\'s name.",
                default: packageInfo.name
            }
        }
    }, function(err, result) {
        callback(err, result);
    })

}

// match the arguments to test if there is a supported license type
function doMatch(callback) {
    var licenses = Object.keys(licenseTpls);
    var matachedIdx = '';

    var matached = licenses.some(function(element, idx, arr) {
        matachedIdx = idx;
        return args.indexOf(element) >= 0;
    })

    if(matached) {
        callback(null, licenses[matachedIdx]);
    } else {
        callback({
            code: '001',
            msg: 'license not supported'
        }, matachedIdx)
    }

}

function genLice(licenseType, config, callback) {
    var license = licenseTpls[licenseType];
    var ws = fs.createWriteStream('./LICENSE', {
        flags: 'w',
        encoding: 'utf8'
    });

    var compiled = _.template(license.body);

    ws.end(compiled(config));

    ws.on('finish', function(err, result) {
        callback(err, result);
    })
}<commit_msg>add arguments support<commit_after>#! /usr/bin/env node

var fs = require('fs');
var exec = require('child_process').exec;
var prompt = require("prompt");
var program = require('commander');
var _ = require('underscore');
var async = require('async');

var packageInfo = require('./package.json');
var licenseTpls = require('./lib/license_tpl.json');
var args = process.argv.slice(2);

var config = {};
// handle th cmd-line logical and parse options.
if(args.length <= 0) {
    doAsk();
} else if(args.join('').indexOf('-') < 0 && args.indexOf('version') < 0) {
    async.waterfall([
        function(callback) {
            doMatch(null, function(err, result) {
                if(err) console.log(err.msg);
                callback(null, result);
            })
        },
        function(licenseType, callback) {
            getBasicInfo(function(err, result) {
                callback(null, licenseType, result);
            })
        },
        function(licenseType, config, callback) {
            genLice(licenseType, config, function(err, result) {
                if(err) console.error(err);
                console.log('LICENSE has been generated!');
            })
        }
    ]);
} else {
    async.waterfall([
        function(callback) {

            getBasicInfo(function(err, config, remainArgs) {
                if(remainArgs.length <= 0) {

                    prompt.message = "license-gen!".cyan;
                    prompt.delimiter = " ".green;
                    prompt.start();

                    prompt.get({
                        properties: {
                            license: {
                                description: 'Input the license type you want to use.',
                                required: true
                            }
                        }
                    }, function(err, result) {
                        if(err) throw err;
                        callback(null, config, result.license, remainArgs);
                    })
                } else {
                    callback(null, config, null, remainArgs);
                }

            });
        },
        function(config, licenseType, remainArgs, callback) {
            if(!licenseType) {
                doMatch(remainArgs, function(err, result) {
                    if(err) console.error(err.msg);
                    callback(null, result, config);
                })
            } else {
                callback(null, licenseType, config);
            }
        },
        function(licenseType, config, callback) {
            genLice(licenseType, config, function(err, result) {
                if(err) console.error(err);
                console.log('LICENSE has been generated!');
            })
        }
    ]);
}

function getBasicInfo(callback) {
    async.waterfall([
        function(callback) {
            program
                .description('Use this command to generate a license file.')
                .version(packageInfo.version)
                .option('-a, --author <author>', 'Your name.', packageInfo.author)
                .option('-y, --year <year>', 'Year used in your license.', new Date().getFullYear())
                .option('-p, --project <project>', 'Project\'s name', packageInfo.name)
                .parse(process.argv);

            config = {
                author: program.author,
                year: program.year,
                project: program.project
            };

            remainArgs = program.args;

            callback(null, config, remainArgs);
        },
        function(config, remainArgs, callback) {

            // if no project name in package.json, use dir name insteed.
            if(!config.project) {
                config.project = __dirname.split('/').pop();
            }

            // if neither [-a] arg provided nor author info in package.json, use git config insteed.
            // TODO, if none of these specify an author name.
            if(!config.author) {
                exec('git config --get user.name', function(err, stdout, stderr) {
                    if(err) throw err;
                    config.author = stdout.replace(/[\n\r]/g, '');
                    callback(null, config, remainArgs);
                })
            } else {
                callback(null, config, remainArgs);
            }
        }
    ], function(err, result, remainArgs) {
        callback(err, result, remainArgs);
    });
}

function doAsk(callback) {
    prompt.message = "license-gen!".cyan;
    prompt.delimiter = " ".green;
    prompt.start();

    prompt.get({
        properties: {
            author: {
                description: "Input your name.",
                message: 'You must specify your name',
                required: true
            },
            year: {
                type: 'number',
                description: "Input the year to used inyour license.",
                message: "You should input a number or leave blank to use current year.",
                default: new Date().getFullYear()
            },
            project: {
                description: "Input the project\'s name.",
                default: packageInfo.name
            }
        }
    }, function(err, result) {
        callback(err, result);
    })

}

// match the arguments to test if there is a supported license type
function doMatch(arr, callback) {
    var licenses = Object.keys(licenseTpls);
    var matachedIdx = '';
    arr = arr || args;

    var matached = licenses.some(function(element, idx, originArr) {
        matachedIdx = idx;
        return arr.indexOf(element) >= 0;
    })

    if(matached) {
        callback(null, licenses[matachedIdx]);
    } else {
        callback({
            code: '001',
            msg: 'license not supported'
        }, matachedIdx)
    }

}

function genLice(licenseType, config, callback) {
    var license = licenseTpls[licenseType];
    var ws = fs.createWriteStream('./LICENSE', {
        flags: 'w',
        encoding: 'utf8'
    });

    var compiled = _.template(license.body);

    ws.end(compiled(config));

    ws.on('finish', function(err, result) {
        callback(err, result);
    })
}<|endoftext|>


<commit_before>"use strict";

var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var url = require('url');

var Base64Decode = require('base64-stream').Decode;
var fileUrl = require('file-url');
var merge = require('merge');
var objectHash = require('object-hash');
var phantomjs = require('phantomjs').path;
var viewports = require('viewportsizes');

exports = module.exports = shashin;

var defaults = {
	phantomTimeout: 300,
	timeout: 30,
	https: false,
	delay: 0,
	crop: false,
	selector: null,
	zoomFactor: 1
};

function shashin (uri, resolution, options, callback) {
	var task = prepareTask(merge(true,
		defaults,
		{ uri: uri, resolution: resolution },
		options
	));

	return merge(info(task), { stream: takeScreenshot(task) });
}

function info (task) {
	var info = {
		hash: objectHash(task),
		url: task.uri,
		width: task.width,
		height: task.height,
		crop: task.crop,
		delay: task.delay,
		selector: task.selector,
		zoomFactor: task.zoomFactor
	};

	return info;
}

function takeScreenshot (task) {
	var stream = new Base64Decode();
	var err = validateTask(task);

	if (err) {
		process.nextTick(function () {
			stream.emit('error', err);
			stream.end();
		});

	} else {
		var proc = spawn(phantomjs, [
			path.join(__dirname, 'phantom-screenshot.js'),
			JSON.stringify(task),
			'--ignore-ssl-errors=true',
			'--ssl-protocol=any',
			'--local-to-remote-url-access=true'
		]);

		proc.stdout.pipe(stream);

		var killTimer = setTimeout(function () {
			stream.emit('error', new Error('Process timed out'));
			stream.end();
			proc.kill();
		}, task.phantomTimeout * 1000);

		proc.stderr.on('data', function (data) {
			stream.emit('error', new Error(data.toString('utf8').trim()));
			stream.end();
		});

		proc.on('exit', function (code) {
			clearTimeout(killTimer);
		});
	}

	return stream;
}

function prepareTask (task) {
	var isFile = fs.existsSync(task.uri);
	var protocol = task.https ? 'https://' : 'http://';

	if (isFile) {
		task.uri = fileUrl(task.uri);
	} else {
		task.uri = (!task.uri) ? '' : url.parse(task.uri).protocol ? task.uri : protocol + task.uri;
		var uriParts = url.parse(task.uri);
		task.uri = url.format(uriParts);
	}

	task = merge(task, parseSize(task.resolution));

	if (task.size) {
		var size = parseSize(task.size);
		var resolution = parseSize(task.resolution);
		var aspect = resolution.width / resolution.height;
		var newWidth, newHeight;

		if (aspect > 1) {
			newWidth = size.width;
			newHeight = resolution.height / aspect;
		} else {
			newWidth = resolution.width * aspect;
			newHeight = size.height;
		}

		task = merge(task, {
			width: newWidth,
			height: newHeight,
			zoomFactor: newWidth / resolution.width
		});
	}

	return task;
}

function validateTask (task) {
	var uriParts = url.parse(task.uri);

	if (uriParts.protocol !== 'file:' && (!uriParts.protocol || !uriParts.host)) {
		return new Error('Invalid argument: Missing or invalid URL.');
	}

	if (!task.width || !task.height) {
		return new Error('Invalid argument: Missing or invalid resoultion.');
	}

	if (task.timeout > task.phantomTimeout) {
		return new Error('Invalid options: phantomTimeout must be greater than timeout.');
	}

	if (task.delay > task.timeout) {
		return new Error('Invalid options: timeout must be greater than delay.');
	}
}

function parseSize (size) {
	if (size && typeof size === 'string') {
		if (/^\d+x\d+$/i.test(size)) {
			size = size.split(/x/i);
		} else {
			var vp = viewports.get(size);
			size = (vp) ? vp.size || null : null;
		}
	}

	if (size && Array.isArray(size) && size.length === 2) {
		return { width: parseInt(size[0], 10), height: parseInt(size[1], 10) };
	}

	if (size && typeof size === 'object' && size.hasOwnProperty('width') && size.hasOwnProperty('height')) {
		return size;
	}

	return null;
}
<commit_msg>remove dead code<commit_after>"use strict";

var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var url = require('url');

var Base64Decode = require('base64-stream').Decode;
var fileUrl = require('file-url');
var merge = require('merge');
var objectHash = require('object-hash');
var phantomjs = require('phantomjs').path;
var viewports = require('viewportsizes');

exports = module.exports = shashin;

var defaults = {
	phantomTimeout: 300,
	timeout: 30,
	https: false,
	delay: 0,
	crop: false,
	selector: null,
	zoomFactor: 1
};

function shashin (uri, resolution, options, callback) {
	var task = prepareTask(merge(true,
		defaults,
		{ uri: uri, resolution: resolution },
		options
	));

	return merge(info(task), { stream: takeScreenshot(task) });
}

function info (task) {
	var info = {
		hash: objectHash(task),
		url: task.uri,
		width: task.width,
		height: task.height,
		crop: task.crop,
		delay: task.delay,
		selector: task.selector,
		zoomFactor: task.zoomFactor
	};

	return info;
}

function takeScreenshot (task) {
	var stream = new Base64Decode();
	var err = validateTask(task);

	if (err) {
		process.nextTick(function () {
			stream.emit('error', err);
			stream.end();
		});

	} else {
		var proc = spawn(phantomjs, [
			path.join(__dirname, 'phantom-screenshot.js'),
			JSON.stringify(task),
			'--ignore-ssl-errors=true',
			'--ssl-protocol=any',
			'--local-to-remote-url-access=true'
		]);

		proc.stdout.pipe(stream);

		var killTimer = setTimeout(function () {
			stream.emit('error', new Error('Process timed out'));
			stream.end();
			proc.kill();
		}, task.phantomTimeout * 1000);

		proc.stderr.on('data', function (data) {
			stream.emit('error', new Error(data.toString('utf8').trim()));
			stream.end();
		});

		proc.on('exit', function (code) {
			clearTimeout(killTimer);
		});
	}

	return stream;
}

function prepareTask (task) {
	var isFile = fs.existsSync(task.uri);
	var protocol = task.https ? 'https://' : 'http://';

	if (isFile) {
		task.uri = fileUrl(task.uri);
	} else {
		task.uri = (!task.uri) ? '' : url.parse(task.uri).protocol ? task.uri : protocol + task.uri;
		var uriParts = url.parse(task.uri);
		task.uri = url.format(uriParts);
	}

	task = merge(task, parseSize(task.resolution));

	return task;
}

function validateTask (task) {
	var uriParts = url.parse(task.uri);

	if (uriParts.protocol !== 'file:' && (!uriParts.protocol || !uriParts.host)) {
		return new Error('Invalid argument: Missing or invalid URL.');
	}

	if (!task.width || !task.height) {
		return new Error('Invalid argument: Missing or invalid resoultion.');
	}

	if (task.timeout > task.phantomTimeout) {
		return new Error('Invalid options: phantomTimeout must be greater than timeout.');
	}

	if (task.delay > task.timeout) {
		return new Error('Invalid options: timeout must be greater than delay.');
	}
}

function parseSize (size) {
	if (size && typeof size === 'string') {
		if (/^\d+x\d+$/i.test(size)) {
			size = size.split(/x/i);
		} else {
			var vp = viewports.get(size);
			size = (vp) ? vp.size || null : null;
		}
	}

	if (size && Array.isArray(size) && size.length === 2) {
		return { width: parseInt(size[0], 10), height: parseInt(size[1], 10) };
	}

	if (size && typeof size === 'object' && size.hasOwnProperty('width') && size.hasOwnProperty('height')) {
		return size;
	}

	return null;
}
<|endoftext|>


<commit_before>module.exports = {
  extends: 'airbnb',
  plugins: ['babel'],
  parser: 'babel-eslint',
  env: {
    // allow browser globals
    browser: true,
  },
  rules: {
    // allow parens around arrow functions only when necessary (0 or >=2 args)
    'arrow-parens': [2, 'as-needed'],

    // require trailing commas in all contexts except function calls
    'comma-dangle': [2, 'always-multiline'],

    // allow require() calls
    'global-require': 0,

    // ensure that default, named, and namespaced imports have been exported by the target file
    'import/default': 2,
    'import/named': 2,
    'import/namespace': 2,

    // require all module imports to be declared as (dev-)dependencies in package.json
    'import/no-extraneous-dependencies': [2, {devDependencies: true}],

    // require import groups to be ordered by specificity and separated by linebreaks
    'import/order': [2, {'newlines-between': 'always'}],

    // allow files with a single named export (to allow in-progress util files)
    'import/prefer-default-export': 0,

    // allow non-ID-linked <label>s to accomodate those containing linked <input>s
    'jsx-a11y/label-has-for': 0,

    // require single quotes in JSX
    'jsx-quotes': [2, 'prefer-single'],

    // require multi-line operators to occur at the start of the line, except && and ||
    'operator-linebreak': [2, 'before', {overrides: {'&&': 'after', '||': 'after'}}],

    // allow supposedly-confusing arrows
    'no-confusing-arrow': 0,

    // do not allow more than one empty line anywhere
    'no-multiple-empty-lines': [2, {max: 1, maxEOF: 1}],

    // disallow confusing global browser variables
    'no-restricted-globals': ['error', 'event', 'find'],

    // allow variable shadowing, just for convenience
    // TODO: enable?
    'no-shadow': 0,

    // allow dangling underscores in variable names (for "private" class methods)
    'no-underscore-dangle': 0,

    // disallow spaces in between curly braces
    'babel/object-curly-spacing': [2, 'never'],
    'object-curly-spacing': 0,

    // disallow .jsx files for consistency
    'react/jsx-filename-extension': 0,

    // do not require a React import to use JSX (it's included automatically in our Babel preset)
    'react/react-in-jsx-scope': 0,

    // do not require default props for optional props
    'react/require-default-props': 0,

    // disallow semicolons
    'semi': [2, 'never'],

    // don't enforce JSX indentation, due to bugginess of the linter implementation :(
    // TODO: https://github.com/yannickcr/eslint-plugin-react/issues/540
    'react/jsx-indent': 0,
    'react/jsx-indent-props': 0,
    'react/jsx-closing-bracket-location': 0,

    // TODO: enable when less buggy
    'react/no-unused-prop-types': 0,

    // allow event listeners on static elements (e.g. onClick on divs)
    'jsx-a11y/no-static-element-interactions': 0,
  },
  settings: {
    // do not attempt to parse npm modules or non-JS files for exports
    'import/ignore': [
      'node_modules',
      '\.(png|svg|jpg|css|pdf)$'
    ],
    'import/extensions': [
      '.js'
    ],
  },
}
<commit_msg>Allow computed references to namespace imports<commit_after>module.exports = {
  extends: 'airbnb',
  plugins: ['babel'],
  parser: 'babel-eslint',
  env: {
    // allow browser globals
    browser: true,
  },
  rules: {
    // allow parens around arrow functions only when necessary (0 or >=2 args)
    'arrow-parens': [2, 'as-needed'],

    // require trailing commas in all contexts except function calls
    'comma-dangle': [2, 'always-multiline'],

    // allow require() calls
    'global-require': 0,

    // ensure that default, named, and namespaced imports have been exported by the target file
    'import/default': 2,
    'import/named': 2,
    'import/namespace': [2, {allowComputed: true}],

    // require all module imports to be declared as (dev-)dependencies in package.json
    'import/no-extraneous-dependencies': [2, {devDependencies: true}],

    // require import groups to be ordered by specificity and separated by linebreaks
    'import/order': [2, {'newlines-between': 'always'}],

    // allow files with a single named export (to allow in-progress util files)
    'import/prefer-default-export': 0,

    // allow non-ID-linked <label>s to accomodate those containing linked <input>s
    'jsx-a11y/label-has-for': 0,

    // require single quotes in JSX
    'jsx-quotes': [2, 'prefer-single'],

    // require multi-line operators to occur at the start of the line, except && and ||
    'operator-linebreak': [2, 'before', {overrides: {'&&': 'after', '||': 'after'}}],

    // allow supposedly-confusing arrows
    'no-confusing-arrow': 0,

    // do not allow more than one empty line anywhere
    'no-multiple-empty-lines': [2, {max: 1, maxEOF: 1}],

    // disallow confusing global browser variables
    'no-restricted-globals': ['error', 'event', 'find'],

    // allow variable shadowing, just for convenience
    // TODO: enable?
    'no-shadow': 0,

    // allow dangling underscores in variable names (for "private" class methods)
    'no-underscore-dangle': 0,

    // disallow spaces in between curly braces
    'babel/object-curly-spacing': [2, 'never'],
    'object-curly-spacing': 0,

    // disallow .jsx files for consistency
    'react/jsx-filename-extension': 0,

    // do not require a React import to use JSX (it's included automatically in our Babel preset)
    'react/react-in-jsx-scope': 0,

    // do not require default props for optional props
    'react/require-default-props': 0,

    // disallow semicolons
    'semi': [2, 'never'],

    // don't enforce JSX indentation, due to bugginess of the linter implementation :(
    // TODO: https://github.com/yannickcr/eslint-plugin-react/issues/540
    'react/jsx-indent': 0,
    'react/jsx-indent-props': 0,
    'react/jsx-closing-bracket-location': 0,

    // TODO: enable when less buggy
    'react/no-unused-prop-types': 0,

    // allow event listeners on static elements (e.g. onClick on divs)
    'jsx-a11y/no-static-element-interactions': 0,
  },
  settings: {
    // do not attempt to parse npm modules or non-JS files for exports
    'import/ignore': [
      'node_modules',
      '\.(png|svg|jpg|css|pdf)$'
    ],
    'import/extensions': [
      '.js'
    ],
  },
}
<|endoftext|>