<commit_before>/**
 * Module Dependencies
 */

var _ = require('./subdash')
var maps = require('./maps.json')

/**
 * The T string regex, e.g. "t:=9h,dt:12h", to encode T = <t> <dt>. Is case sensitive.
 */

var reT = /t\:\S*,dt\:\S*/g

/**
 * The ordering of time units, large to small,
 * 'mer' is the meridiem, 0 for am, 1 for pm
 */

var timeUnitOrder = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms', 'mer']

/**
 * Delimiters for ISO string
 */

var ISOdelim = ['-', '-', 'T', ':', ':', 'Z'];

/**
 * Export `util`
 */

module.exports = {
  reT: reT,
  timeUnitOrder: timeUnitOrder,
  ISOdelim: ISOdelim,
  lemma: lemma,
  sName: sName,
  ISOtoT: ISOtoT,
  TtoISO: TtoISO,
  splitT: splitT,
  nowT: nowT,
  TtoStr: TtoStr,
  splitByArr: splitByArr,
  delimSyms: delimSyms,
  splitSyms: splitSyms,
  orderChunks: orderChunks,
  hasSym: hasSym,
  isSym: isSym,
  opType: opType,
  lowestOverride: lowestOverride,
}

/**
 * Return the lemma symbol of a word string, i.e. the name and value of the symbol it belongs to in the CFG. Uses ./maps.json.
 * NLP Lemmatization refers here: htp://nlp.stanford.edu/Ir-book/html/htmledition/stemming-and-lemmatization-1.html. Inflections = all possible alternative words of a lemma.
 * @param  {string} str To lemmatize.
 * @return {JSON}     Lemma symbol {name, value} for CFG
 * @example
 * lemma('zero')
 * // => { value: '0', name: 'n' }
 */
function lemma(str) {
  // change all to lower case except for 'M' for month
  str = (str == 'M') ? str : str.toLowerCase()
  var lem = {},
    name = null,
    value = null;
  var mapsKeys = _.keys(maps);
  for (var i = 0; i < mapsKeys.length; i++) {
    var sMap = maps[mapsKeys[i]],
      sMapKeys = _.keys(sMap);
    for (var j = 0; j < sMapKeys.length; j++) {
      var inflectionArr = sMap[sMapKeys[j]];
      if (_.includes(inflectionArr, str)) {
        // if str is in inflections
        value = sMapKeys[j]
        break
      };
    }
    if (value != null) {
      name = mapsKeys[i]
      break
    };
  }
  // set value
  lem['name'] = name
  lem['value'] = value;
  return lem
}
// console.log(lemma('zero'))

/**
 * Return the name of a symbol: {op,c,r,n,T,f}
 * @param  {Symbol} symbol A CFG symbol.
 * @return {string}        name of the symbol.
 */
function sName(symbol) {
  return symbol ? symbol.constructor.name : null;
}

/**
 * Convert ISO UTC string to T string.
 * @example
 * ISOtoT('2011-10-05T14:48:00.000Z')
 * // => 't:2011y10M05d14h48m00.000s,dt:'
 */
function ISOtoT(str) {
  var datetime = str.replace('Z', '').split('T')
  var date = datetime[0].split('-'),
    time = datetime[1].split(':');
  return 't:' + date[0] + 'y' + date[1] + 'M' + date[2] + 'd' + time[0] + 'h' + time[1] + 'm' + time[2] + 's,dt:'
}
// console.log(ISOtoT('2011-10-05T14:48:00.000Z'))

/**
 * Convert a T string to ISO UTC string, with default filled by nowT().
 * @example
 * TtoISO('t:10M05d14h48m00.000s,dt:')
 * // => 2016-10-05T14:48:00.000Z
 */
function TtoISO(str) {
  var
    nowArr = splitT(nowT()),
    strArr = splitT(str),
    res = '';
  for (var i = 0; i < nowArr.length; i++) {
    var num = strArr[i] == undefined ? nowArr[i] : strArr[i];
    res += (num + ISOdelim[i])
  }
  return res
}
// console.log(TtoISO('t:10M05d14h48m00.000s,dt:'))

/**
 * Split a T string into array of [_y, _M, _d, _h, _m, _s]
 */
function splitT(str) {
  if (!str.match(reT)) {
    return null;
  }
  var
    _y = (/(\d+)y/.exec(str) || [])[1],
    _M = (/(\d+)M/.exec(str) || [])[1],
    _d = (/(\d+)d/.exec(str) || [])[1],
    _h = (/(\d+)h/.exec(str) || [])[1],
    _m = (/(\d+)m/.exec(str) || [])[1],
    _s = (/(\d+(\.\d+))s/.exec(str) || [])[1]
  return [_y, _M, _d, _h, _m, _s]
}

/**
 * Convenient method to get current time in T format.
 * @return {string} T format string.
 */
function nowT() {
  var dateStr = new Date().toISOString();
  return ISOtoT(dateStr)
}

/**
 * Convert a T symbol into its T string.
 */
function TtoStr(T) {
  var tStr = 't:',
    dtStr = ',dt:';
  for (var i = 0; i < timeUnitOrder.length; i++) {
    var tUnit = timeUnitOrder[i];
    // if unit exist, write to str
    if (T['t'][tUnit]) {
      tStr += T['t'][tUnit] + tUnit;
    };
    if (T['dt'][tUnit]) {
      dtStr += T['dt'][tUnit] + tUnit;
    };
  }
  return tStr + dtStr
}

/**
 * Split a string by an array of tokens.
 * @param  {string} str       The input string.
 * @param  {Array} tokenArr Array of tokens to split the string by.
 * @return {Array}           The split string array.
 */
function splitByArr(str, tokenArr) {
  var delim = '#{REPLACE}';
  // inject into tokens
  for (var i = 0; i < tokenArr.length; i++) {
    var token = tokenArr[i];
    str = str.replace(token, delim)
  }
  // split into arr
  return str.split(delim)
}
// console.log(splitByArr('lorem 1 ipsum 2 dolor 3', [1,2,3]))

/**
 * Delimit the array of timeChunk symbols by combining consecutive nulls (>3) into one, and dumping those shorter. Result is then delimited by 'trinull'.
 * @param  {Array} syms Of parsed symbols aka time chunks.
 * @return {Array}      symbols delimited by 'trinull'
 */
function delimSyms(syms) {
  // 1.
  // contract the nulls into trinulls in a single array
  var newSyms = [],
    count = 0;
  for (var i = 0; i < syms.length; i++) {
    var s = syms[i];
    if (s == null) {
      count++;
    } else {
      if (count > 2) {
        newSyms.push('trinull')
      };
      newSyms.push(s);
      count = 0;
    }
  }
  return newSyms
}
// console.log(delimSyms([1, 2, null, null, null, 3]))

/**
 * Split an array of symbols by delimiter into matrix.
 * @param  {Array} syms      The input array
 * @param  {string|symbol} delimiter To split the array by
 * @return {matrix}           delimited arrays.
 */
function splitSyms(syms, delimiter) {
  // split the single array into matrix
  var matrix = [],
    newRow = [];
  for (var i = 0; i < syms.length; i++) {
    var s = syms[i];
    if (s == delimiter || sName(s) == delimiter) {
      // delimit and push to matrix
      matrix.push(newRow)
      newRow = [];
    } else if (i == syms.length - 1) {
      // edge case, push res
      newRow.push(s)
      matrix.push(newRow)
    } else {
      // accumulate in row
      newRow.push(s)
    }
  }
  return matrix
}

/**
 * Order time chunks by not containing T, short to long, then containing T, short to long. Used for .pop() to get the candidate timechunk for parsing.
 */
function orderChunks(matrix) {
  // 2.
  // ok partition first then sort
  var hasNoT = matrix.filter(function(row) {
    return !hasSym(row, ['T'])
  })
  var hasT = matrix.filter(function(row) {
    return hasSym(row, ['T'])
  })
  // matrix, sorted short to long
  var lengthSortedNotTMat = hasNoT.sort(function(a, b) {
    return a.length - b.length
  })
  var lengthSortedTMat = hasT.sort(function(a, b) {
    return a.length - b.length
  })
  // 3.1 3.2 3.3
  return lengthSortedNotTMat.concat(lengthSortedTMat)
}

/**
 * Check if arr has symbol whose name is listen in symArr.
 * @param  {Array}  arr    Array of symbols.
 * @param  {Array}  symArr Array of symbol names.
 * @return {Boolean}
 */
function hasSym(syms, symArr) {
  var found = false;
  for (var i = 0; i < syms.length; i++) {
    if (isSym(syms[i], symArr)) {
      found = true
      break
    };
  }
  return found;
}

/**
 * Check if arr has the symbol name of s.
 * @param  {symbol}  s   symbol object
 * @param  {Array}  arr Of string symbol names
 * @return {Boolean}
 */
function isSym(s, arr) {
  return _.includes(arr, sName(s))
}

/**
 * Determine the op type based on arguments
 */
function opType(L, op, R) {
  var LsName = sName(L) || '',
    RsName = sName(R) || '';
  var opsName = sName(op);
  if (opsName != 'o' && opsName != 'r' && opsName != 'c') { opsName = '' };
  return LsName + opsName + RsName
}

/**
 * find the lowest overridable unit in t or dt
 */
function lowestOverride(t) {
  var lowestOverable = null;
  for (var i = timeUnitOrder.length - 1; i >= 0; i--) {
    var unit = timeUnitOrder[i]
    if (/^=/.exec(t[unit])) {
      lowestOverable = unit;
      break
    }
  }
  return lowestOverable
}

// lowestOverride({
//   y: '10',
//   M: '=20',
//   w: '=30',
//   d: '40'
// })<commit_msg>fix TtoISO prepend 0 if needed<commit_after>/**
 * Module Dependencies
 */

var _ = require('./subdash')
var maps = require('./maps.json')

/**
 * The T string regex, e.g. "t:=9h,dt:12h", to encode T = <t> <dt>. Is case sensitive.
 */

var reT = /t\:\S*,dt\:\S*/g

/**
 * The ordering of time units, large to small,
 * 'mer' is the meridiem, 0 for am, 1 for pm
 */

var timeUnitOrder = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms', 'mer']

/**
 * Delimiters for ISO string
 */

var ISOdelim = ['-', '-', 'T', ':', ':', 'Z'];

/**
 * Export `util`
 */

module.exports = {
  reT: reT,
  timeUnitOrder: timeUnitOrder,
  ISOdelim: ISOdelim,
  lemma: lemma,
  sName: sName,
  ISOtoT: ISOtoT,
  TtoISO: TtoISO,
  splitT: splitT,
  nowT: nowT,
  TtoStr: TtoStr,
  splitByArr: splitByArr,
  delimSyms: delimSyms,
  splitSyms: splitSyms,
  orderChunks: orderChunks,
  hasSym: hasSym,
  isSym: isSym,
  opType: opType,
  lowestOverride: lowestOverride,
}

/**
 * Return the lemma symbol of a word string, i.e. the name and value of the symbol it belongs to in the CFG. Uses ./maps.json.
 * NLP Lemmatization refers here: htp://nlp.stanford.edu/Ir-book/html/htmledition/stemming-and-lemmatization-1.html. Inflections = all possible alternative words of a lemma.
 * @param  {string} str To lemmatize.
 * @return {JSON}     Lemma symbol {name, value} for CFG
 * @example
 * lemma('zero')
 * // => { value: '0', name: 'n' }
 */
function lemma(str) {
  // change all to lower case except for 'M' for month
  str = (str == 'M') ? str : str.toLowerCase()
  var lem = {},
    name = null,
    value = null;
  var mapsKeys = _.keys(maps);
  for (var i = 0; i < mapsKeys.length; i++) {
    var sMap = maps[mapsKeys[i]],
      sMapKeys = _.keys(sMap);
    for (var j = 0; j < sMapKeys.length; j++) {
      var inflectionArr = sMap[sMapKeys[j]];
      if (_.includes(inflectionArr, str)) {
        // if str is in inflections
        value = sMapKeys[j]
        break
      };
    }
    if (value != null) {
      name = mapsKeys[i]
      break
    };
  }
  // set value
  lem['name'] = name
  lem['value'] = value;
  return lem
}
// console.log(lemma('zero'))

/**
 * Return the name of a symbol: {op,c,r,n,T,f}
 * @param  {Symbol} symbol A CFG symbol.
 * @return {string}        name of the symbol.
 */
function sName(symbol) {
  return symbol ? symbol.constructor.name : null;
}

/**
 * Convert ISO UTC string to T string.
 * @example
 * ISOtoT('2011-10-05T14:48:00.000Z')
 * // => 't:2011y10M05d14h48m00.000s,dt:'
 */
function ISOtoT(str) {
  var datetime = str.replace('Z', '').split('T')
  var date = datetime[0].split('-'),
    time = datetime[1].split(':');
  return 't:' + date[0] + 'y' + date[1] + 'M' + date[2] + 'd' + time[0] + 'h' + time[1] + 'm' + time[2] + 's,dt:'
}
// console.log(ISOtoT('2011-10-05T14:48:00.000Z'))

/**
 * Convert a T string to ISO UTC string, with default filled by nowT().
 * @example
 * TtoISO('t:10M05d14h48m00.000s,dt:')
 * // => 2016-10-05T14:48:00.000Z
 */
function TtoISO(str) {
  var nowStr = nowT(),
    nowArr = splitT(nowStr),
    strArr = splitT(str);
  var resArr = [];
  for (var i = 0; i < nowArr.length; i++) {
    var val = parseFloat(strArr[i]) || parseFloat(nowArr[i])
    resArr.push(val)
  }
  var resStr = '',
    ISOdelim = ['-', '-', 'T', ':', ':', 'Z'];
  for (var i = 0; i < ISOdelim.length; i++) {
    var num = resArr[i].toString();
    // e.g. '05' tends to be '5', fix it
    if (num.length == 1) { num = '0' + num };
    resStr += (num + ISOdelim[i])
  }
  return resStr
}
// console.log(TtoISO('t:10M05d14h48m00.000s,dt:'))

/**
 * Split a T string into array of [_y, _M, _d, _h, _m, _s]
 */
function splitT(str) {
  if (!str.match(reT)) {
    return null;
  }
  var
    _y = (/(\d+)y/.exec(str) || [])[1],
    _M = (/(\d+)M/.exec(str) || [])[1],
    _d = (/(\d+)d/.exec(str) || [])[1],
    _h = (/(\d+)h/.exec(str) || [])[1],
    _m = (/(\d+)m/.exec(str) || [])[1],
    _s = (/(\d+(\.\d+))s/.exec(str) || [])[1]
  return [_y, _M, _d, _h, _m, _s]
}

/**
 * Convenient method to get current time in T format.
 * @return {string} T format string.
 */
function nowT() {
  var dateStr = new Date().toISOString();
  return ISOtoT(dateStr)
}

/**
 * Convert a T symbol into its T string.
 */
function TtoStr(T) {
  var tStr = 't:',
    dtStr = ',dt:';
  for (var i = 0; i < timeUnitOrder.length; i++) {
    var tUnit = timeUnitOrder[i];
    // if unit exist, write to str
    if (T['t'][tUnit]) {
      tStr += T['t'][tUnit] + tUnit;
    };
    if (T['dt'][tUnit]) {
      dtStr += T['dt'][tUnit] + tUnit;
    };
  }
  return tStr + dtStr
}

/**
 * Split a string by an array of tokens.
 * @param  {string} str       The input string.
 * @param  {Array} tokenArr Array of tokens to split the string by.
 * @return {Array}           The split string array.
 */
function splitByArr(str, tokenArr) {
  var delim = '#{REPLACE}';
  // inject into tokens
  for (var i = 0; i < tokenArr.length; i++) {
    var token = tokenArr[i];
    str = str.replace(token, delim)
  }
  // split into arr
  return str.split(delim)
}
// console.log(splitByArr('lorem 1 ipsum 2 dolor 3', [1,2,3]))

/**
 * Delimit the array of timeChunk symbols by combining consecutive nulls (>3) into one, and dumping those shorter. Result is then delimited by 'trinull'.
 * @param  {Array} syms Of parsed symbols aka time chunks.
 * @return {Array}      symbols delimited by 'trinull'
 */
function delimSyms(syms) {
  // 1.
  // contract the nulls into trinulls in a single array
  var newSyms = [],
    count = 0;
  for (var i = 0; i < syms.length; i++) {
    var s = syms[i];
    if (s == null) {
      count++;
    } else {
      if (count > 2) {
        newSyms.push('trinull')
      };
      newSyms.push(s);
      count = 0;
    }
  }
  return newSyms
}
// console.log(delimSyms([1, 2, null, null, null, 3]))

/**
 * Split an array of symbols by delimiter into matrix.
 * @param  {Array} syms      The input array
 * @param  {string|symbol} delimiter To split the array by
 * @return {matrix}           delimited arrays.
 */
function splitSyms(syms, delimiter) {
  // split the single array into matrix
  var matrix = [],
    newRow = [];
  for (var i = 0; i < syms.length; i++) {
    var s = syms[i];
    if (s == delimiter || sName(s) == delimiter) {
      // delimit and push to matrix
      matrix.push(newRow)
      newRow = [];
    } else if (i == syms.length - 1) {
      // edge case, push res
      newRow.push(s)
      matrix.push(newRow)
    } else {
      // accumulate in row
      newRow.push(s)
    }
  }
  return matrix
}

/**
 * Order time chunks by not containing T, short to long, then containing T, short to long. Used for .pop() to get the candidate timechunk for parsing.
 */
function orderChunks(matrix) {
  // 2.
  // ok partition first then sort
  var hasNoT = matrix.filter(function(row) {
    return !hasSym(row, ['T'])
  })
  var hasT = matrix.filter(function(row) {
      return hasSym(row, ['T'])
    })
    // matrix, sorted short to long
  var lengthSortedNotTMat = hasNoT.sort(function(a, b) {
    return a.length - b.length
  })
  var lengthSortedTMat = hasT.sort(function(a, b) {
      return a.length - b.length
    })
    // 3.1 3.2 3.3
  return lengthSortedNotTMat.concat(lengthSortedTMat)
}

/**
 * Check if arr has symbol whose name is listen in symArr.
 * @param  {Array}  arr    Array of symbols.
 * @param  {Array}  symArr Array of symbol names.
 * @return {Boolean}
 */
function hasSym(syms, symArr) {
  var found = false;
  for (var i = 0; i < syms.length; i++) {
    if (isSym(syms[i], symArr)) {
      found = true
      break
    };
  }
  return found;
}

/**
 * Check if arr has the symbol name of s.
 * @param  {symbol}  s   symbol object
 * @param  {Array}  arr Of string symbol names
 * @return {Boolean}
 */
function isSym(s, arr) {
  return _.includes(arr, sName(s))
}

/**
 * Determine the op type based on arguments
 */
function opType(L, op, R) {
  var LsName = sName(L) || '',
    RsName = sName(R) || '';
  var opsName = sName(op);
  if (opsName != 'o' && opsName != 'r' && opsName != 'c') { opsName = '' };
  return LsName + opsName + RsName
}

/**
 * find the lowest overridable unit in t or dt
 */
function lowestOverride(t) {
  var lowestOverable = null;
  for (var i = timeUnitOrder.length - 1; i >= 0; i--) {
    var unit = timeUnitOrder[i]
    if (/^=/.exec(t[unit])) {
      lowestOverable = unit;
      break
    }
  }
  return lowestOverable
}

// lowestOverride({
//   y: '10',
//   M: '=20',
//   w: '=30',
//   d: '40'
// })
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var path = require('path');
var util = require('util');
var css = require('@nuintun/css-deps');
var debug = require('debug')('gulp-css');
var plugins = require('./plugins/index');
var gutil = require('@nuintun/gulp-util');

var join = path.join;

// set debug color use 6
debug.color = 6;

/**
 * rename
 *
 * @param {any} path
 * @param {any} transform
 * @returns {String}
 */
function rename(path, transform) {
  return gutil.rename(path, transform, debug);
}

/**
 * transport
 *
 * @param {any} vinyl
 * @param {any} options
 * @param {any} done
 * @returns {void}
 */
function transport(vinyl, options, done) {
  return gutil.transport(vinyl, options, done, debug);
}

/**
 * resolve
 *
 * @param {any} relative
 * @param {any} vinyl
 * @param {any} wwwroot
 * @returns {String}
 */
function resolve(relative, vinyl, wwwroot) {
  return gutil.resolve(relative, vinyl, wwwroot, debug);
}

/**
 * pring
 *
 * @returns {void}
 */
function print() {
  var message = gutil.apply(util.format, null, gutil.slice.call(arguments));

  process.stdout.write(gutil.colors.cyan.bold('  gulp-css ') + message + '\n');
}

/**
 * get rename options
 *
 * @param transform
 * @returns {object}
 */
function initRenameOptions(transform) {
  if (gutil.isFunction(transform)) {
    return transform;
  }

  transform = transform || {};

  if (transform.min) {
    transform.suffix = '-min';
  }

  if (transform.debug) {
    transform.suffix = '-debug';
  }

  return transform;
}

/**
 * init options
 *
 * @param options
 * @returns {object}
 */
function initOptions(options) {
  options = gutil.extend(true, {
    include: false, // include
    prefix: null, // css prefix
    onpath: null, // css resource path callback
    cache: true, // use memory file cahe
    wwwroot: '', // web root
    rename: null // { debug: boolean, min: boolean }
  }, options);

  // wwwroot must be string
  if (!gutil.isString(options.wwwroot)) {
    gutil.throwError('options.wwwroot\'s value should be string.');
  }

  // init wwwroot
  options.wwwroot = join(gutil.cwd, options.wwwroot);
  // init plugins
  options.plugins = gutil.plugins(options.plugins, plugins);
  // init rename
  options.rename = initRenameOptions(options.rename);

  return options;
}

/**
 * transport css dependencies.
 *
 * @param vinyl
 * @param options
 * @returns {Array}
 */
function transportCssDeps(vinyl, options) {
  var deps = [];
  var remote = [];
  var include = [];
  var pkg = vinyl.package || {};
  var onpath = options.onpath;
  var prefix = options.prefix;

  // init css settings
  onpath = gutil.isFunction(onpath) ? function(path, property) {
    return options.onpath(path, property, vinyl.path, options.wwwroot);
  } : null;

  prefix = gutil.isFunction(prefix) ? prefix(vinyl.path, options.wwwroot) : prefix;

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(css(vinyl.contents, function(id) {
    var path;

    // id is not a local file
    if (!gutil.isLocal(id)) {
      // cache dependencie id
      deps.push(id);
      remote.push(id);
    } else {
      // normalize id
      id = gutil.normalize(id);

      // if end with /, find index file
      if (id.substring(id.length - 1) === '/') {
        id += 'index.css';
      }

      // set path
      path = id;
      // rename id
      id = rename(path, options.rename);

      // normalize id
      id = gutil.normalize(id);

      // debug
      debug('transport deps: %s', colors.magenta(id));

      // get absolute path
      path = resolve(path, vinyl, options.wwwroot);

      // cache dependencie id
      deps.push(id);
      // cache dependencie absolute path
      include.push(path);
    }

    // include import css file
    if (options.include) {
      // delete all import
      return false;
    }

    // onpath callback
    if (gutil.isString(path = onpath(id, 'import'))) {
      return path;
    }

    // don't make changes
    return id;
  }, { prefix: prefix, onpath: onpath }));

  // cache file dependencies
  vinyl.package = gutil.extend(pkg, {
    remote: remote,
    include: include,
    dependencies: deps
  });

  return deps;
}

/**
 * exports module
 */
module.exports = {
  debug: debug,
  rename: rename,
  transport: transport,
  resolve: resolve,
  print: print,
  initOptions: initOptions,
  transportCssDeps: transportCssDeps
};
<commit_msg>update files<commit_after>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var path = require('path');
var util = require('util');
var css = require('@nuintun/css-deps');
var debug = require('debug')('gulp-css');
var gutil = require('@nuintun/gulp-util');

var join = path.join;

// set debug color use 6
debug.color = 6;

/**
 * rename
 *
 * @param {any} path
 * @param {any} transform
 * @returns {String}
 */
function rename(path, transform) {
  return gutil.rename(path, transform, debug);
}

/**
 * transport
 *
 * @param {any} vinyl
 * @param {any} options
 * @param {any} done
 * @returns {void}
 */
function transport(vinyl, options, done) {
  return gutil.transport(vinyl, options, done, debug);
}

/**
 * resolve
 *
 * @param {any} relative
 * @param {any} vinyl
 * @param {any} wwwroot
 * @returns {String}
 */
function resolve(relative, vinyl, wwwroot) {
  return gutil.resolve(relative, vinyl, wwwroot, debug);
}

/**
 * pring
 *
 * @returns {void}
 */
function print() {
  var message = gutil.apply(util.format, null, gutil.slice.call(arguments));

  process.stdout.write(gutil.colors.cyan.bold('  gulp-css ') + message + '\n');
}

/**
 * get rename options
 *
 * @param transform
 * @returns {object}
 */
function initRenameOptions(transform) {
  if (gutil.isFunction(transform)) {
    return transform;
  }

  transform = transform || {};

  if (transform.min) {
    transform.suffix = '-min';
  }

  if (transform.debug) {
    transform.suffix = '-debug';
  }

  return transform;
}

/**
 * init options
 *
 * @param options
 * @returns {object}
 */
function initOptions(options) {
  options = gutil.extend(true, {
    include: false, // include
    prefix: null, // css prefix
    onpath: null, // css resource path callback
    cache: true, // use memory file cahe
    wwwroot: '', // web root
    rename: null // { debug: boolean, min: boolean }
  }, options);

  // wwwroot must be string
  if (!gutil.isString(options.wwwroot)) {
    gutil.throwError('options.wwwroot\'s value should be string.');
  }

  // init wwwroot
  options.wwwroot = join(gutil.cwd, options.wwwroot);
  // init plugins
  options.plugins = gutil.plugins(options.plugins, require('./plugins/index'));
  // init rename
  options.rename = initRenameOptions(options.rename);

  return options;
}

/**
 * transport css dependencies.
 *
 * @param vinyl
 * @param options
 * @returns {Array}
 */
function transportCssDeps(vinyl, options) {
  var deps = [];
  var remote = [];
  var include = [];
  var pkg = vinyl.package || {};
  var onpath = options.onpath;
  var prefix = options.prefix;

  // init css settings
  onpath = gutil.isFunction(onpath) ? function(path, property) {
    return options.onpath(path, property, vinyl.path, options.wwwroot);
  } : null;

  prefix = gutil.isFunction(prefix) ? prefix(vinyl.path, options.wwwroot) : prefix;

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(css(vinyl.contents, function(id) {
    var path;

    // id is not a local file
    if (!gutil.isLocal(id)) {
      // cache dependencie id
      deps.push(id);
      remote.push(id);
    } else {
      // normalize id
      id = gutil.normalize(id);

      // if end with /, find index file
      if (id.substring(id.length - 1) === '/') {
        id += 'index.css';
      }

      // set path
      path = id;
      // rename id
      id = rename(path, options.rename);

      // normalize id
      id = gutil.normalize(id);

      // debug
      debug('transport deps: %s', colors.magenta(id));

      // get absolute path
      path = resolve(path, vinyl, options.wwwroot);

      // cache dependencie id
      deps.push(id);
      // cache dependencie absolute path
      include.push(path);
    }

    // include import css file
    if (options.include) {
      // delete all import
      return false;
    }

    // onpath callback
    if (gutil.isString(path = onpath(id, 'import'))) {
      return path;
    }

    // don't make changes
    return id;
  }, { prefix: prefix, onpath: onpath }));

  // cache file dependencies
  vinyl.package = gutil.extend(pkg, {
    remote: remote,
    include: include,
    dependencies: deps
  });

  return deps;
}

/**
 * exports module
 */
module.exports = {
  debug: debug,
  rename: rename,
  transport: transport,
  resolve: resolve,
  print: print,
  initOptions: initOptions,
  transportCssDeps: transportCssDeps
};
<|endoftext|>


<commit_before>'use strict';

const urlParser = require('url');

// Priorities list of matchers
const MIME_TYPE_MATCHERS = [
  [/^text\/html/, 'html'],
  [/^text\/plain/, 'plain'],
  [/^text\/css/, 'css'],
  [/javascript/, 'javascript'],
  [/flash/, 'flash'],
  [/^image\/x-icon/, 'favicon'],
  [/^image\/vnd.microsoft.icon/, 'favicon'],
  [/svg/, 'svg'],
  [/^image/, 'image'],
  [/^application\/.*font/, 'font'],
  [/^font\/.*/, 'font'],
  [/^application\/json/, 'json'],
  [/^application\/ocsp-response/, 'oscp'],
  [/.*/, 'other'] // Always match 'other' if all else fails
];

/**
 * Utilities for getting content from HAR:s.
 * @module util
 */
module.exports = {
  /**
   * Get the content type from mime type.
   * @param {string} mimeType The mimeType
   * @returns {string} the content type or 'other'.
   */
  getContentType: mimeType =>
    MIME_TYPE_MATCHERS.find(matcher => matcher[0].test(mimeType))[1],

  getHTTPVersion: version => {
    if (version === 'h2' || version === 'HTTP/2.0') {
      return 'HTTP/2.0';
    } else if (version.indexOf('spdy') > -1) {
      return version.toUpperCase();
    }
    return version.toUpperCase();
  },
  getConnectionType: version => {
    if (version === 'h2' || version === 'HTTP/2.0') {
      return 'h2';
    } else if (version.indexOf('spdy') > -1) {
      return 'spdy';
    }
    return 'h1';
  },
  /**
   * Get the hostname from a URL string.
   * @param {string} url The URL like https://www.example.com/hepp
   * @returns {string} the hostname
   */
  getHostname: url => {
    if (!url) {
      return '';
    }

    return urlParser.parse(url).hostname || '';
  },
  /**
   * Get the final URL for a HAR file. Lets start with the tested URL
   * and check if it is redirected, and then report the last URL
   * @param {string} url The url to check.
   * @param {Object} har The har.
   * @param {Object} pageId
   * @returns {Object} final url and redirect chain.
   * @throws if har doesn't have exactly one page
   */
  getRedirectTarget: (url, har, pageId) => {
    const chain = [];
    const redirections = har.log.entries
      .filter(entry => {
        return pageId !== undefined ? entry.pageref === pageId : true;
      })
      .reduce((results, entry) => {
        let destination = entry.response.redirectURL;
        if (destination) {
          if (destination.startsWith('/')) {
            destination = urlParser.resolve(entry.request.url, destination);
          }
          results[entry.request.url] = destination;
        }
        return results;
      }, {});
    let nextUrl = redirections[url];
    // Fixes https://github.com/sitespeedio/pagexray/issues/50
    // for now
    redirections[url] = undefined;
    while (nextUrl) {
      chain.push(nextUrl);
      nextUrl = redirections[nextUrl];
      // Right now we aren't the best in the world to handle redirects back
      // and forth to the same page but it's kind of an edge case with redirects
      // like:
      // hepp --> hopp --> hepp --> happ --> hepp --> hipp
      // https://github.com/sitespeedio/pagexray/issues/50
      redirections[url] = undefined;
    }
    const finalUrl = chain.length > 0 ? chain[chain.length - 1] : url;
    return {
      finalUrl,
      chain
    };
  },
  getEntryByURL(entries, url, pageId) {
    // Chrome and Chrome-HAR strips everything after #
    // Firefox keeps it
    const myEntry = entries.find(
      entry => entry.request.url === url && entry.pageref === pageId
    );
    // Try without #
    if (!myEntry) {
      const withoutHash = url.split('#')[0];
      return entries.find(
        entry => entry.request.url === withoutHash && entry.pageref === pageId
      );
    } else {
      return myEntry;
    }
  }
};
<commit_msg>Treat unknown HTTP version as unknown #53 (#54)<commit_after>'use strict';

const urlParser = require('url');

// Priorities list of matchers
const MIME_TYPE_MATCHERS = [
  [/^text\/html/, 'html'],
  [/^text\/plain/, 'plain'],
  [/^text\/css/, 'css'],
  [/javascript/, 'javascript'],
  [/flash/, 'flash'],
  [/^image\/x-icon/, 'favicon'],
  [/^image\/vnd.microsoft.icon/, 'favicon'],
  [/svg/, 'svg'],
  [/^image/, 'image'],
  [/^application\/.*font/, 'font'],
  [/^font\/.*/, 'font'],
  [/^application\/json/, 'json'],
  [/^application\/ocsp-response/, 'oscp'],
  [/.*/, 'other'] // Always match 'other' if all else fails
];

/**
 * Utilities for getting content from HAR:s.
 * @module util
 */
module.exports = {
  /**
   * Get the content type from mime type.
   * @param {string} mimeType The mimeType
   * @returns {string} the content type or 'other'.
   */
  getContentType: mimeType =>
    MIME_TYPE_MATCHERS.find(matcher => matcher[0].test(mimeType))[1],

  getHTTPVersion: version => {
    if (version === 'h2' || version === 'HTTP/2.0') {
      return 'HTTP/2.0';
    } else if (version.indexOf('spdy') > -1) {
      return version.toUpperCase();
    } else if (version === '') {
      return 'Unknown';
    }
    return version.toUpperCase();
  },
  getConnectionType: version => {
    if (version === 'h2' || version === 'HTTP/2.0') {
      return 'h2';
    } else if (version.indexOf('spdy') > -1) {
      return 'spdy';
    } else if (version === '') {
      return 'Unknown';
    }
    return 'h1';
  },
  /**
   * Get the hostname from a URL string.
   * @param {string} url The URL like https://www.example.com/hepp
   * @returns {string} the hostname
   */
  getHostname: url => {
    if (!url) {
      return '';
    }

    return urlParser.parse(url).hostname || '';
  },
  /**
   * Get the final URL for a HAR file. Lets start with the tested URL
   * and check if it is redirected, and then report the last URL
   * @param {string} url The url to check.
   * @param {Object} har The har.
   * @param {Object} pageId
   * @returns {Object} final url and redirect chain.
   * @throws if har doesn't have exactly one page
   */
  getRedirectTarget: (url, har, pageId) => {
    const chain = [];
    const redirections = har.log.entries
      .filter(entry => {
        return pageId !== undefined ? entry.pageref === pageId : true;
      })
      .reduce((results, entry) => {
        let destination = entry.response.redirectURL;
        if (destination) {
          if (destination.startsWith('/')) {
            destination = urlParser.resolve(entry.request.url, destination);
          }
          results[entry.request.url] = destination;
        }
        return results;
      }, {});
    let nextUrl = redirections[url];
    // Fixes https://github.com/sitespeedio/pagexray/issues/50
    // for now
    redirections[url] = undefined;
    while (nextUrl) {
      chain.push(nextUrl);
      nextUrl = redirections[nextUrl];
      // Right now we aren't the best in the world to handle redirects back
      // and forth to the same page but it's kind of an edge case with redirects
      // like:
      // hepp --> hopp --> hepp --> happ --> hepp --> hipp
      // https://github.com/sitespeedio/pagexray/issues/50
      redirections[url] = undefined;
    }
    const finalUrl = chain.length > 0 ? chain[chain.length - 1] : url;
    return {
      finalUrl,
      chain
    };
  },
  getEntryByURL(entries, url, pageId) {
    // Chrome and Chrome-HAR strips everything after #
    // Firefox keeps it
    const myEntry = entries.find(
      entry => entry.request.url === url && entry.pageref === pageId
    );
    // Try without #
    if (!myEntry) {
      const withoutHash = url.split('#')[0];
      return entries.find(
        entry => entry.request.url === withoutHash && entry.pageref === pageId
      );
    } else {
      return myEntry;
    }
  }
};
<|endoftext|>


<commit_before>'use strict';

angular.module('jlogApp.services')
    .value('scores', {
        va: {
            result: 'victory',
            type: 'assassination'
        },
        vc: {
            result: 'victory',
            type: 'clock'
        },
        vs: {
            result: 'victory',
            type: 'scenario'
        },
        dd: {
            result: 'draw',
            type: 'dice down'
        },
        da: {
            result: 'defeat',
            type: 'assassination'
        },
        dc: {
            result: 'defeat',
            type: 'clock'
        },
        ds: {
            result: 'defeat',
            type: 'scenario'
        }
    });
<commit_msg>Added tiebreaker scores.<commit_after>'use strict';

angular.module('jlogApp.services')
    .value('scores', {
        va: {
            result: 'victory',
            type: 'assassination'
        },
        vc: {
            result: 'victory',
            type: 'clock'
        },
        vs: {
            result: 'victory',
            type: 'scenario'
        },
        vt: {
            result: 'victory',
            type: 'tiebreaker'
        },
        dd: {
            result: 'draw',
            type: 'dice down'
        },
        da: {
            result: 'defeat',
            type: 'assassination'
        },
        dc: {
            result: 'defeat',
            type: 'clock'
        },
        ds: {
            result: 'defeat',
            type: 'scenario'
        },
        dt: {
            result: 'defeat',
            type: 'tiebreaker'
        }
    });
<|endoftext|>


<commit_before>/**
 *  class SassEngine
 *
 *  Engine for the SASS/SCSS compiler. You will need `node-sass` Node module installed
 *  in order to use [[Mincer]] with `*.sass` or `*.scss` files:
 *
 *      npm install node-sass
 *
 *
 *  ##### SUBCLASS OF
 *
 *  [[Template]]
 **/

'use strict';

// stdlib
var path = require('path');

// 3rd-party
var _ = require('lodash');
var sass; // initialized later

// internal
var Template  = require('../template');
var prop      = require('../common').prop;

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

// Class constructor
var SassEngine = module.exports = function SassEngine() {
  Template.apply(this, arguments);
  sass = sass || Template.libs['node-sass'] || require('node-sass');

  // Ensure node sass module has renderSync method
  if (!sass.renderSync) {
    throw new Error('node-sass < v0.5 is not supported.');
  }
};

require('util').inherits(SassEngine, Template);

// helper to generate human-friendly errors.
// adapted version from less_engine.js
function sassError(ctx /*, options*/) {
  // libsass error string format: path:line: error: message
  var error = _.zipObject(
    [ 'path', 'line', 'level', 'message' ],
    ctx.split(':', 4).map(function(str) { return str.trim(); })
  );
  if (error.line && error.level && error.message) {
    return new Error('Line ' + error.line + ': ' + error.message);
  }

  return new Error(ctx);
}

// Render data
SassEngine.prototype.evaluate = function (context/*, locals*/) {
  try {
    this.data = sass.renderSync({
      data:         this.data,
      includePaths: [ path.dirname(this.file) ].concat(context.environment.paths)
    });
  } catch(err) {
    var error = sassError(err);
    throw error;
  }
};

// Expose default MimeType of an engine
prop(SassEngine, 'defaultMimeType', 'text/css');
<commit_msg>Added support for SASS Indented Syntax.<commit_after>/**
 *  class SassEngine
 *
 *  Engine for the SASS/SCSS compiler. You will need `node-sass` Node module installed
 *  in order to use [[Mincer]] with `*.sass` or `*.scss` files:
 *
 *      npm install node-sass
 *
 *
 *  ##### SUBCLASS OF
 *
 *  [[Template]]
 **/

'use strict';

// stdlib
var path = require('path');

// 3rd-party
var _ = require('lodash');
var sass; // initialized later

// internal
var Template  = require('../template');
var prop      = require('../common').prop;

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

// Class constructor
var SassEngine = module.exports = function SassEngine() {
  Template.apply(this, arguments);
  sass = sass || Template.libs['node-sass'] || require('node-sass');

  // Ensure node sass module has renderSync method
  if (!sass.renderSync) {
    throw new Error('node-sass < v0.5 is not supported.');
  }
};

require('util').inherits(SassEngine, Template);

// helper to generate human-friendly errors.
// adapted version from less_engine.js
function sassError(ctx /*, options*/) {
  // libsass error string format: path:line: error: message
  var error = _.zipObject(
    [ 'path', 'line', 'level', 'message' ],
    ctx.split(':', 4).map(function(str) { return str.trim(); })
  );
  if (error.line && error.level && error.message) {
    return new Error('Line ' + error.line + ': ' + error.message);
  }

  return new Error(ctx);
}

// Render data
SassEngine.prototype.evaluate = function (context/*, locals*/) {
  try {
    this.data = sass.renderSync({
      data:         this.data,
      includePaths: [ path.dirname(this.file) ].concat(context.environment.paths),
      indentedSyntax: /^.*\.sass$/.test(this.file)
    });
  } catch(err) {
    var error = sassError(err);
    throw error;
  }
};

// Expose default MimeType of an engine
prop(SassEngine, 'defaultMimeType', 'text/css');
<|endoftext|>


<commit_before>var async = require('async');
var fs = require('fs');
var later = require('later');
var path = require('path');

/**
 * A simple list of events so we know what is an event and what isn't!
 */
var EVENTS = [ 'start', 'stop' ];

var LOCKING = (function () {
  var LOCKNAME = 'cron.lock';
  var LOCKPATH = path.join(__dirname, LOCKNAME);

  return {
    start: function (times, callback) {
      if (IS_RUNNING) return callback(Error('You cannot run the Cron library twice'));

      if (module.parent && module.parent.filename) {
        LOCKNAME = path.basename(module.parent.filename, path.extname(module.parent.filename)) + '.lock';
        LOCKPATH = path.join(path.dirname(module.parent.filename), LOCKNAME);
      }

      console.log('Locking with', LOCKPATH);

      fs.access(LOCKPATH, function (err) {
        if (err && err.code !== 'ENOENT') return callback(err || new Error('Cron already running'));
        fs.writeFile(LOCKPATH, '1', 'utf8', callback);
      });
    },
    stop: function (callback) {
      IS_RUNNING = false;
      fs.unlink(LOCKPATH, callback);
    }
  };
})();

var IS_RUNNING = false;

/**
 * Introducing, the Cron!
 */
function Cron() {
  this._alias = {};
  this._help = {};

  this._crons = {};
  this._events = {};
}

/**
 * A mapping of times to aliases
 * See the README or aliases.json for the exact structure you can use
 */
Cron.prototype.aliases = function (mapping) {
  for (var time in mapping) /* istanbul ignore else */ if (mapping.hasOwnProperty(time)) {
    if (!Array.isArray(mapping[time])) mapping[time] = [ mapping[time] ];
    for (var i = 0; i < mapping[time].length; i++) this._alias[mapping[time][i]] = time;
  }
  return this;
};

var transformFns = function (fn) {
  if (fn.length === 0) return function (callback) {
    try {
      var r = fn();
      if (r && typeof r.then === 'function') {
        r.then(function () {
          callback();
        }, function (err) {
          callback(err);
        });
      }
      else callback();
    }
    catch (e) {
      callback(e);
    }
  };
  if (fn.length === 1) return fn;
};

/**
 * Adds functions to run when a specific cron-time is matched
 * A "cron-time" can be in the standard UNIX cron format OR a pre-defined alias OR it can be a specific event
 * Either way, it will be executed at runtime
 *
 * @param {String} cronTime A time, or an alias, or an event
 * (@param {String} cronDescription An optional description for the cron job)
 * @param {Function|Array[Function]} cronFn Functions expecting a single "callback" argument
 * @return {Cron} Returns the current instance for chaining
 */
Cron.prototype.on = function (cronTime, cronDescription, cronFn) {
  if (typeof cronDescription === 'function' || Array.isArray(cronDescription)) {
    cronFn = cronDescription;
    cronDescription = null;
  }

  var target = EVENTS.indexOf(cronTime.toString().toLowerCase()) >= 0 ? '_events' : '_crons';
  if (target === '_crons' && this._alias.hasOwnProperty(cronTime)) cronTime = this._alias[cronTime];

  this[target][cronTime] = this[target][cronTime] || [];
  if (Array.isArray(cronFn)) this[target][cronTime] = this[target][cronTime].concat(cronFn.map(transformFns));
  else this[target][cronTime].push(transformFns(cronFn));

  if (cronDescription) {
    this._help[target] = this._help[target] || {};
    this._help[target][cronTime] = this._help[target][cronTime] || [];
    this._help[target][cronTime].push(cronDescription);
  }

  return this;
};

/**
 * List all the help descriptions stored in an easy-to-understand list!
 *
 * @return {String}
 */
Cron.prototype.list = function () {
  var out = [];

  if (this._events && this._events.start && this._events.start.length > 0) {
    out.push('start (' + this._events.start.length + ' event' + (this._events.start.length === 1 ? '' : 's') + ')');
    if (this._help._events && this._help._events.start) {
      out = out.concat(this._help._events.start.map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
    out.push('');
  }

  for (var time in this._crons) if (this._crons.hasOwnProperty(time)) {
    out.push(time + ' (' + this._crons[time].length + ' event' + (this._crons[time].length === 1 ? '' : 's') + ')');
    if (this._help._crons && this._help._crons[time]) {
      out = out.concat(this._help._crons[time].map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
    out.push('');
  }

  if (this._events && this._events.stop && this._events.stop.length > 0) {
    out.push('stop (' + this._events.stop.length + ' event' + (this._events.stop.length === 1 ? '' : 's') + ')');
    if (this._help._events && this._help._events.stop) {
      out = out.concat(this._help._events.stop.map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
  }

  return out.join('\n');
};

/**
 * Initiate the cron jobs
 * Works out the current time down to the nearest minute, filters out all the jobs that don't match and run the rest
 *
 * (@param {String[]} args An optional array of string arguments)
 * (@param {Function} callback An optional callback function to run on completion (takes a single error argument))
 * @return void
 */
Cron.prototype.run = function (args, callback) {
  /* istanbul ignore next */
  if (!args && !callback) {
    args = process.argv.slice(2);
    callback = null;
  }

  if (typeof args === 'function') {
    callback = args;
    args = process.argv.slice(2);
  }

  /* istanbul ignore next */
  if (!callback) callback = function (err) {
    if (err) console.error(err.stack ? err.stack : err.toString());
    process.exit(err ? 1 : 0);
  };

  if (IS_RUNNING) return callback(new Error('You cannot run the Cron library twice'));
  IS_RUNNING = true;

  var date = new Date();
  var opts = {
    use_locking: (args.indexOf('--no-locking') < 0)
  };

  /**
   * If we have a set of arguments, then run them.
   */
  if (args.length > 0) {
    /* istanbul ignore next */
    if (args[0] === 'list') {
      console.log(this.list());
      return callback();
    }
    else if (args[0] === 'test') {
      this._crons.every_minute = this._crons.every_minute || [];
      for (var p in this._crons) if (p !== 'every_minute' && this._crons.hasOwnProperty(p)) {
        this._crons.every_minute = this._crons.every_minute.concat(this._crons[p]);
        this._crons[p] = [];
      }
    }
    else if (args[0].indexOf(':') > 0) {
      date.setHours(
        parseInt(args[0].substr(0, args[0].indexOf(':')), 10),
        parseInt(args[0].substr(args[0].indexOf(':') + 1), 10)
      );
    }
  }

  date.setSeconds(0); // Date has seconds, and we don't want seconds

  var fns = [];
  var times = [];
  Object.keys(this._crons).forEach(function (time) {
    if (later.schedule(later.parse.cron(time)).isValid(date)) {
      fns = fns.concat(this._crons[time]);
      times.push(time);
    }
  }.bind(this));

  this._events.start = this._events.start || [];
  this._events.stop = this._events.stop || [];

  if (opts.use_locking && LOCKING.start && LOCKING.stop) {
    this._events.start.unshift(LOCKING.start.bind(null, times));
    this._events.stop.unshift(LOCKING.stop.bind(null, times));
  }

  async.series([].concat(
    this._events.start,
    [ async.parallel.bind(async.parallel, fns) ],
    this._events.stop
  ), function (err) {
    if (err && IS_RUNNING && opts.use_locking && LOCKING.stop) {
      return LOCKING.stop(function () {
        callback(err);
      });
    }
    else callback(err);
  });
};

/**
 * On emergency-exit situations, call just the stop functions.
 *
 * @param {Function} callback A callback argument taking an error function
 */
Cron.prototype.stop = function (callback) {
  async.series(Array.isArray(this._events.stop) ? this._events.stop : [], function (err) {
    if (IS_RUNNING && LOCKING.stop) LOCKING.stop(function () { callback(err); });
    else callback(err);
  });
};

var cronfile = new Cron();
cronfile.aliases(require('./aliases.json'));

module.exports = cronfile;
<commit_msg>This layout looks neater<commit_after>var async = require('async');
var fs = require('fs');
var later = require('later');
var path = require('path');

/**
 * A simple list of events so we know what is an event and what isn't!
 */
var EVENTS = [ 'start', 'stop' ];

var LOCKING = (function () {
  var LOCKING = {};
  var LOCKNAME = 'cron.lock';
  var LOCKPATH = path.join(__dirname, LOCKNAME);

  LOCKING.start = function (times, callback) {
    if (IS_RUNNING) return callback(Error('You cannot run the Cron library twice'));

    if (module.parent && module.parent.filename) {
      LOCKNAME = path.basename(module.parent.filename, path.extname(module.parent.filename)) + '.lock';
      LOCKPATH = path.join(path.dirname(module.parent.filename), LOCKNAME);
    }

    console.log('Locking with', LOCKPATH);

    fs.access(LOCKPATH, function (err) {
      if (err && err.code !== 'ENOENT') return callback(err || new Error('Cron already running'));
      fs.writeFile(LOCKPATH, '1', 'utf8', callback);
    });
  };

  LOCKING.stop = function (callback) {
    IS_RUNNING = false;
    fs.unlink(LOCKPATH, callback);
  };

  return LOCKING;
})();

var IS_RUNNING = false;

/**
 * Introducing, the Cron!
 */
function Cron() {
  this._alias = {};
  this._help = {};

  this._crons = {};
  this._events = {};
}

/**
 * A mapping of times to aliases
 * See the README or aliases.json for the exact structure you can use
 */
Cron.prototype.aliases = function (mapping) {
  for (var time in mapping) /* istanbul ignore else */ if (mapping.hasOwnProperty(time)) {
    if (!Array.isArray(mapping[time])) mapping[time] = [ mapping[time] ];
    for (var i = 0; i < mapping[time].length; i++) this._alias[mapping[time][i]] = time;
  }
  return this;
};

var transformFns = function (fn) {
  if (fn.length === 0) return function (callback) {
    try {
      var r = fn();
      if (r && typeof r.then === 'function') {
        r.then(function () {
          callback();
        }, function (err) {
          callback(err);
        });
      }
      else callback();
    }
    catch (e) {
      callback(e);
    }
  };
  if (fn.length === 1) return fn;
};

/**
 * Adds functions to run when a specific cron-time is matched
 * A "cron-time" can be in the standard UNIX cron format OR a pre-defined alias OR it can be a specific event
 * Either way, it will be executed at runtime
 *
 * @param {String} cronTime A time, or an alias, or an event
 * (@param {String} cronDescription An optional description for the cron job)
 * @param {Function|Array[Function]} cronFn Functions expecting a single "callback" argument
 * @return {Cron} Returns the current instance for chaining
 */
Cron.prototype.on = function (cronTime, cronDescription, cronFn) {
  if (typeof cronDescription === 'function' || Array.isArray(cronDescription)) {
    cronFn = cronDescription;
    cronDescription = null;
  }

  var target = EVENTS.indexOf(cronTime.toString().toLowerCase()) >= 0 ? '_events' : '_crons';
  if (target === '_crons' && this._alias.hasOwnProperty(cronTime)) cronTime = this._alias[cronTime];

  this[target][cronTime] = this[target][cronTime] || [];
  if (Array.isArray(cronFn)) this[target][cronTime] = this[target][cronTime].concat(cronFn.map(transformFns));
  else this[target][cronTime].push(transformFns(cronFn));

  if (cronDescription) {
    this._help[target] = this._help[target] || {};
    this._help[target][cronTime] = this._help[target][cronTime] || [];
    this._help[target][cronTime].push(cronDescription);
  }

  return this;
};

/**
 * List all the help descriptions stored in an easy-to-understand list!
 *
 * @return {String}
 */
Cron.prototype.list = function () {
  var out = [];

  if (this._events && this._events.start && this._events.start.length > 0) {
    out.push('start (' + this._events.start.length + ' event' + (this._events.start.length === 1 ? '' : 's') + ')');
    if (this._help._events && this._help._events.start) {
      out = out.concat(this._help._events.start.map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
    out.push('');
  }

  for (var time in this._crons) if (this._crons.hasOwnProperty(time)) {
    out.push(time + ' (' + this._crons[time].length + ' event' + (this._crons[time].length === 1 ? '' : 's') + ')');
    if (this._help._crons && this._help._crons[time]) {
      out = out.concat(this._help._crons[time].map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
    out.push('');
  }

  if (this._events && this._events.stop && this._events.stop.length > 0) {
    out.push('stop (' + this._events.stop.length + ' event' + (this._events.stop.length === 1 ? '' : 's') + ')');
    if (this._help._events && this._help._events.stop) {
      out = out.concat(this._help._events.stop.map(function (cronDescription) {
        return '- ' + cronDescription;
      }));
    }
  }

  return out.join('\n');
};

/**
 * Initiate the cron jobs
 * Works out the current time down to the nearest minute, filters out all the jobs that don't match and run the rest
 *
 * (@param {String[]} args An optional array of string arguments)
 * (@param {Function} callback An optional callback function to run on completion (takes a single error argument))
 * @return void
 */
Cron.prototype.run = function (args, callback) {
  /* istanbul ignore next */
  if (!args && !callback) {
    args = process.argv.slice(2);
    callback = null;
  }

  if (typeof args === 'function') {
    callback = args;
    args = process.argv.slice(2);
  }

  /* istanbul ignore next */
  if (!callback) callback = function (err) {
    if (err) console.error(err.stack ? err.stack : err.toString());
    process.exit(err ? 1 : 0);
  };

  if (IS_RUNNING) return callback(new Error('You cannot run the Cron library twice'));
  IS_RUNNING = true;

  var date = new Date();
  var opts = {
    use_locking: (args.indexOf('--no-locking') < 0)
  };

  /**
   * If we have a set of arguments, then run them.
   */
  if (args.length > 0) {
    /* istanbul ignore next */
    if (args[0] === 'list') {
      console.log(this.list());
      return callback();
    }
    else if (args[0] === 'test') {
      this._crons.every_minute = this._crons.every_minute || [];
      for (var p in this._crons) if (p !== 'every_minute' && this._crons.hasOwnProperty(p)) {
        this._crons.every_minute = this._crons.every_minute.concat(this._crons[p]);
        this._crons[p] = [];
      }
    }
    else if (args[0].indexOf(':') > 0) {
      date.setHours(
        parseInt(args[0].substr(0, args[0].indexOf(':')), 10),
        parseInt(args[0].substr(args[0].indexOf(':') + 1), 10)
      );
    }
  }

  date.setSeconds(0); // Date has seconds, and we don't want seconds

  var fns = [];
  var times = [];
  Object.keys(this._crons).forEach(function (time) {
    if (later.schedule(later.parse.cron(time)).isValid(date)) {
      fns = fns.concat(this._crons[time]);
      times.push(time);
    }
  }.bind(this));

  this._events.start = this._events.start || [];
  this._events.stop = this._events.stop || [];

  if (opts.use_locking && LOCKING.start && LOCKING.stop) {
    this._events.start.unshift(LOCKING.start.bind(null, times));
    this._events.stop.unshift(LOCKING.stop.bind(null, times));
  }

  async.series([].concat(
    this._events.start,
    [ async.parallel.bind(async.parallel, fns) ],
    this._events.stop
  ), function (err) {
    if (err && IS_RUNNING && opts.use_locking && LOCKING.stop) {
      return LOCKING.stop(function () {
        callback(err);
      });
    }
    else callback(err);
  });
};

/**
 * On emergency-exit situations, call just the stop functions.
 *
 * @param {Function} callback A callback argument taking an error function
 */
Cron.prototype.stop = function (callback) {
  async.series(Array.isArray(this._events.stop) ? this._events.stop : [], function (err) {
    if (IS_RUNNING && LOCKING.stop) LOCKING.stop(function () { callback(err); });
    else callback(err);
  });
};

var cronfile = new Cron();
cronfile.aliases(require('./aliases.json'));

module.exports = cronfile;
<|endoftext|>


<commit_before>/*!
 * util
 * Version: 0.0.1
 * Date: 2017/05/19
 * https://github.com/nuintun/gulp-css
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/nuintun/gulp-css/blob/master/LICENSE
 */

'use strict';

var path = require('path');
var util = require('util');
var css = require('@nuintun/css-deps');
var gutil = require('@nuintun/gulp-util');

var join = path.join;
var dirname = path.dirname;
var cache = new gutil.Cache();
var debug = gutil.debug('gulp-css');

/**
 * rename
 *
 * @param {any} path
 * @param {any} transform
 * @returns {String}
 */
function rename(path, transform) {
  return gutil.rename(path, transform, debug);
}

/**
 * transport
 *
 * @param {any} vinyl
 * @param {any} options
 * @param {any} done
 * @returns {void}
 */
function transport(vinyl, options, done) {
  return gutil.transport(vinyl, options, done, cache, debug);
}

/**
 * resolve a `relative` path base on `base` path
 *
 * @param relative
 * @param vinyl
 * @param wwwroot
 * @returns {String}
 */
function resolve(relative, vinyl, wwwroot) {
  var base;
  var path;

  // resolve
  if (gutil.isAbsolute(relative)) {
    base = wwwroot;
    path = join(base, relative.substring(1));
  } else {
    base = dirname(vinyl.path);
    path = join(base, relative);

    // out of wwwroot
    if (gutil.isOutBound(path, wwwroot)) {
      gutil.throwError('file: %s is out of bound of wwwroot: %s.', gutil.normalize(path), gutil.normalize(wwwroot));
    }
  }

  // debug
  debug('resolve path: %r', path);

  return path;
}

/**
 * pring
 *
 * @returns {void}
 */
function print() {
  var message = gutil.apply(util.format, null, gutil.slice.call(arguments));

  process.stdout.write(gutil.colors.reset.cyan.bold('  gulp-css ') + message + '\n');
}

/**
 * get rename options
 *
 * @param transform
 * @returns {object}
 */
function initRenameOptions(transform) {
  if (gutil.isFunction(transform)) {
    return transform;
  }

  transform = transform || {};

  if (transform.min) {
    transform.suffix = '-min';
  }

  if (transform.debug) {
    transform.suffix = '-debug';
  }

  return transform;
}

/**
 * init options
 *
 * @param options
 * @returns {object}
 */
function initOptions(options) {
  options = gutil.extend(true, {
    include: false, // include
    prefix: null, // css prefix
    onpath: null, // css resource path callback
    cache: true, // use memory file cahe
    wwwroot: '', // web root
    rename: null // { debug: boolean, min: boolean }
  }, options);

  // wwwroot must be string
  if (!gutil.isString(options.wwwroot)) {
    gutil.throwError('options.wwwroot\'s value should be string.');
  }

  // init wwwroot
  options.wwwroot = join(gutil.cwd, options.wwwroot);
  // init plugins
  options.plugins = gutil.plugins(options.plugins, require('./plugins/index'));
  // init rename
  options.rename = initRenameOptions(options.rename);

  return options;
}

/**
 * transport css dependencies.
 *
 * @param vinyl
 * @param options
 * @returns {Array}
 */
function transportCssDeps(vinyl, options) {
  var deps = [];
  var remote = [];
  var include = [];
  var pkg = vinyl.package || {};
  var onpath = options.onpath;
  var prefix = options.prefix;

  // init css settings
  onpath = gutil.isFunction(onpath) ? function(path, property) {
    return options.onpath(path, property, vinyl.path, options.wwwroot);
  } : null;

  prefix = gutil.isFunction(prefix) ? prefix(vinyl.path, options.wwwroot) : prefix;

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(css(vinyl.contents, function(id) {
    var path;

    // id is not a local file
    if (!gutil.isLocal(id)) {
      // cache dependencie id
      deps.push(id);
      remote.push(id);
    } else {
      // normalize id
      id = gutil.normalize(id);

      // if end with /, find index file
      if (id.substring(id.length - 1) === '/') {
        id += 'index.css';
      }

      // set path
      path = id;

      // normalize id
      id = gutil.normalize(id);

      // debug
      debug('module deps: %p', id);

      // get absolute path
      path = resolve(path, vinyl, options.wwwroot);

      // rename id
      id = rename(id, options.rename);

      // cache dependencie id
      deps.push(id);
      // cache dependencie absolute path
      include.push(path);
    }

    // include import css file
    if (options.include) {
      // delete all import
      return false;
    }

    // onpath callback
    if (gutil.isString(path = onpath(id, 'import'))) {
      return path;
    }

    // don't make changes
    return id;
  }, { prefix: prefix, onpath: onpath }));

  // cache file dependencies
  vinyl.package = gutil.extend(pkg, {
    remote: remote,
    include: include,
    dependencies: deps
  });

  return deps;
}

/**
 * exports module
 */
module.exports = {
  debug: debug,
  cache: cache,
  rename: rename,
  transport: transport,
  resolve: resolve,
  print: print,
  initOptions: initOptions,
  transportCssDeps: transportCssDeps
};
<commit_msg>update files<commit_after>/*!
 * util
 * Version: 0.0.1
 * Date: 2017/05/19
 * https://github.com/nuintun/gulp-css
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/nuintun/gulp-css/blob/master/LICENSE
 */

'use strict';

var path = require('path');
var util = require('util');
var css = require('@nuintun/css-deps');
var gutil = require('@nuintun/gulp-util');

var join = path.join;
var dirname = path.dirname;
var cache = new gutil.Cache();
var debug = gutil.debug('gulp-css');

/**
 * rename
 *
 * @param {String} path
 * @param {Function} transform
 * @returns {String}
 */
function rename(path, transform) {
  return gutil.rename(path, transform, debug);
}

/**
 * transport
 *
 * @param {Vinyl} vinyl
 * @param {Object} options
 * @param {Function} done
 * @returns {void}
 */
function transport(vinyl, options, done) {
  return gutil.transport(vinyl, options, done, cache, debug);
}

/**
 * resolve a `relative` path base on `base` path
 *
 * @param {String} relative
 * @param {Vinyl} vinyl
 * @param {String} wwwroot
 * @returns {String}
 */
function resolve(relative, vinyl, wwwroot) {
  var base;
  var path;

  // resolve
  if (gutil.isAbsolute(relative)) {
    base = wwwroot;
    path = join(base, relative.substring(1));
  } else {
    base = dirname(vinyl.path);
    path = join(base, relative);

    // out of wwwroot
    if (gutil.isOutBound(path, wwwroot)) {
      gutil.throwError('file: %s is out of bound of wwwroot: %s.', gutil.normalize(path), gutil.normalize(wwwroot));
    }
  }

  // debug
  debug('resolve path: %r', path);

  return path;
}

/**
 * pring
 *
 * @returns {void}
 */
function print() {
  var message = gutil.apply(util.format, null, gutil.slice.call(arguments));

  process.stdout.write(gutil.colors.reset.cyan.bold('  gulp-css ') + message + '\n');
}

/**
 * get rename options
 *
 * @param {Function} transform
 * @returns {object}
 */
function initRenameOptions(transform) {
  if (gutil.isFunction(transform)) {
    return transform;
  }

  transform = transform || {};

  if (transform.min) {
    transform.suffix = '-min';
  }

  if (transform.debug) {
    transform.suffix = '-debug';
  }

  return transform;
}

/**
 * init options
 *
 * @param {Object} options
 * @returns {object}
 */
function initOptions(options) {
  options = gutil.extend(true, {
    include: false, // include
    prefix: null, // css prefix
    onpath: null, // css resource path callback
    cache: true, // use memory file cahe
    wwwroot: '', // web root
    rename: null // { debug: boolean, min: boolean }
  }, options);

  // wwwroot must be string
  if (!gutil.isString(options.wwwroot)) {
    gutil.throwError('options.wwwroot\'s value should be string.');
  }

  // init wwwroot
  options.wwwroot = join(gutil.cwd, options.wwwroot);
  // init plugins
  options.plugins = gutil.plugins(options.plugins, require('./plugins/index'));
  // init rename
  options.rename = initRenameOptions(options.rename);

  return options;
}

/**
 * transport css dependencies.
 *
 * @param {Vinyl} vinyl
 * @param {Object} options
 * @returns {Array}
 */
function transportCssDeps(vinyl, options) {
  var deps = [];
  var remote = [];
  var include = [];
  var pkg = vinyl.package || {};
  var onpath = options.onpath;
  var prefix = options.prefix;

  // init css settings
  onpath = gutil.isFunction(onpath) ? function(path, property) {
    return options.onpath(path, property, vinyl.path, options.wwwroot);
  } : null;

  prefix = gutil.isFunction(prefix) ? prefix(vinyl.path, options.wwwroot) : prefix;

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(css(vinyl.contents, function(id) {
    var path;

    // onpath callback
    if (gutil.isString(path = onpath(id, 'import'))) {
      id = path;
    }

    // id is not a local file
    if (gutil.isLocal(id)) {
      // normalize id
      id = gutil.normalize(id);

      // if end with /, find index file
      if (id.substring(id.length - 1) === '/') {
        id += 'index.css';
      }

      // debug
      debug('module deps: %p', id);

      // get absolute path
      path = resolve(id, vinyl, options.wwwroot);

      // rename id
      id = rename(id, options.rename);
      // normalize id
      id = gutil.normalize(id);

      // cache dependencie id
      deps.push(id);
      // cache dependencie absolute path
      include.push(path);
    } else {
      // debug
      debug('module remote deps: %p', id);

      // cache dependencie id
      deps.push(id);
      remote.push(id);
    }

    // include import css file
    if (options.include) {
      // delete all import
      return false;
    }

    // don't make changes
    return id;
  }, { prefix: prefix, onpath: onpath }));

  // cache file dependencies
  vinyl.package = gutil.extend(pkg, {
    remote: remote,
    include: include,
    dependencies: deps
  });

  return deps;
}

// exports
module.exports = {
  debug: debug,
  cache: cache,
  rename: rename,
  transport: transport,
  resolve: resolve,
  print: print,
  initOptions: initOptions,
  transportCssDeps: transportCssDeps
};
<|endoftext|>


<commit_before>'use babel';
import 'object-assign-shim';

const tagName = 'minimap-codeglance';

var elementRegistered = false;

var prototype = {
  destroy() {
    this.getModel().destroy();
  },

  show() {
    this.style.opacity = this.clientHeight == 0 ? 0 : '';
    this.style.display = '';
  },

  hide() {
    this.style.display = 'none';
  },

  showLineNumbers() {
    this.removeAttribute('data-hide-gutter');
  },

  hideLineNumbers() {
    this.setAttribute('data-hide-gutter', '');
  },

  setNumberOfLines(numberOfLines) {
    var lineHeight = this.getModel().getLineHeightInPixels();
    this.style.height = numberOfLines * lineHeight + 'px';
  },

  setText(text) {
    this.getModel().setText(text);
  },

  setGrammar(grammar) {
    this.getModel().setGrammar(grammar);
  },

  setSoftWrapped(softWrapped) {
    this.getModel().setSoftWrapped(softWrapped);
  },

  scrollToBufferPosition(bufferPosition) {
    this.getModel().setCursorBufferPosition(bufferPosition, {
      autoscroll: true,
    });
  },

  translateY(offsetY) {
    offsetY -= this.clientHeight / 2;
    offsetY = Math.max(0, offsetY);
    offsetY = Math.min(this.parentNode.clientHeight - this.clientHeight, offsetY);
    requestAnimationFrame(() => this.style.transform = `translateY(${offsetY}px)`);
  },
};

function registerElement() {
  var textEditorElement = document.createElement('atom-text-editor');
  var textEditorElementPrototype = Object.getPrototypeOf(textEditorElement);

  Object.setPrototypeOf(prototype, textEditorElementPrototype);

  document.registerElement(tagName, { prototype });
}

export default function minimapCodeglanceElement() {
  if(!elementRegistered) {
    registerElement();
    elementRegistered = true;
  }
  return document.createElement(tagName);
}
<commit_msg>add some comments<commit_after>'use babel';
import 'object-assign-shim';

const tagName = 'minimap-codeglance';

var elementRegistered = false;

var prototype = {
  destroy() {
    this.getModel().destroy();
  },

  show() {
    this.style.opacity = this.clientHeight == 0 ? 0 : '';
    this.style.display = '';
  },

  hide() {
    this.style.display = 'none';
  },

  showLineNumbers() {
    this.removeAttribute('data-hide-gutter');
  },

  hideLineNumbers() {
    this.setAttribute('data-hide-gutter', '');
  },

  setNumberOfLines(numberOfLines) {
    var lineHeight = this.getModel().getLineHeightInPixels();
    this.style.height = numberOfLines * lineHeight + 'px';
  },

  setText(text) {
    this.getModel().setText(text);
  },

  setGrammar(grammar) {
    this.getModel().setGrammar(grammar);
  },

  setSoftWrapped(softWrapped) {
    this.getModel().setSoftWrapped(softWrapped);
  },

  scrollToBufferPosition(bufferPosition) {
    this.getModel().setCursorBufferPosition(bufferPosition, {
      autoscroll: true,
    });
  },

  translateY(offsetY) {
    offsetY -= this.clientHeight / 2;
    offsetY = Math.max(0, offsetY);
    offsetY = Math.min(this.parentNode.clientHeight - this.clientHeight, offsetY);
    requestAnimationFrame(() => this.style.transform = `translateY(${offsetY}px)`);
  },
};

function registerElement() {
  // extend the atom-text-editor element
  var textEditorElement = document.createElement('atom-text-editor');
  var textEditorElementPrototype = Object.getPrototypeOf(textEditorElement);
  Object.setPrototypeOf(prototype, textEditorElementPrototype);

  document.registerElement(tagName, { prototype });
}

export default function minimapCodeglanceElement() {
  // make sure element is registered
  if(!elementRegistered) {
    registerElement();
    elementRegistered = true;
  }
  return document.createElement(tagName);
}
<|endoftext|>


<commit_before>//
// Vows.js - asynchronous promise-based testing for node.js
//
//   usage:
//
//       var vows = require('vows'),
//           assert = require('assert');
//
//       vows.tell('Deep Thought', function () {
//           question('what is the answer to the universe?').addVow(function (answer) {
//               assert.equals(answer, 42);
//           }, 'it should know the answer to the ultimate question of life');
//       });
//
var sys = require('sys'),
    assert = require('assert'),
    vows = exports;

// Keeps track of the outcome of vows.
var total  = 0, honored = 0,
    broken = 0, errored = 0,
    start, end;

//
// This function gets added to process.Promise.prototype, by default.
// It's essentially a wrapper around `addCallback`, which adds all the specification
// goodness.
//
function addVow(/* description & callback */) {
    var desc, callback;

    function augment(obj) {
        obj = new(obj.constructor)(obj);

        // Recursively augment any Objects
        if (obj instanceof Object) {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) obj[key] = augment(obj[key]);
            }
        }
        for (macro in vows.macros) {
            obj.should[macro] = vows.macros[macro];
        }
        return obj;
    };

    if (arguments.length < 2) throw "A vow is comprised of a description and a proof";

    total++;

    // Sometimes it might be nicer to pass the proof first,
    // and the description second, so we let the user choose
    // the order.
    if (arguments[0] instanceof Function) {
        callback = arguments[0];
        desc     = arguments[1];
    } else {
        desc     = arguments[0];
        callback = arguments[1];
    }

    return this.addCallback(function () {
        var vow = "- ", exception, topics = [], topic;

        for (var i = 0; i < arguments.length; i++) {
            topics[i] = augment(arguments[i]);
        }

        // Run the test, and try to catch `AssertionError`s and other exceptions;
        // increment counters accordingly.
        try {
            callback.apply(null, topics);
            vow += stylize(desc, 'green');
            honored++;
        } catch (e) {
            if (e.name.match(/AssertionError/)) {
                vow += stylize(desc, 'yellow');
                exception = '  ~ ' + stylize("expected " +
                    stylize(sys.inspect(e.expected), 'bold') + ", got " +
                    stylize(sys.inspect(e.actual), 'bold') + "\n", 'yellow');
                broken++;
            } else {
                vow += stylize(desc, 'red');
                exception = '  ! ' + stylize(e.stack, 'red') + "\n";
                errored++;
            }
        }
        sys.puts(vow);

        if (exception) process.stdio.writeError(exception);

        // Output results once all the vows have been checked
        if (honored + broken + errored === total) {
            var result = honored + " honored, " +
                         broken  + " broken, "  +
                         errored + " errored",

            style = honored === total ?
                ('green') : (errored === 0 ? 'yellow' : 'red');

            sys.puts("\nVerified " + total + " vows in " +
                    (((new(Date)) - start) / 1000) + " seconds.");

            sys.puts("\n" + stylize(result, style));
        }
    });
};

vows.macros = {
    equal: function (expected) { assert.equal(obj, expected) },
    match: function (expected) { assert.ok(obj.match(expected)) },
    include: function (item) { assert.ok(obj.match(new(RegExp)(item))) },
    beA: function (type) {
        if (typeof(obj) === 'object') { assert.ok(obj.constructor === type) }
        else {
            if (typeof(type) === 'function') type = type.name.toLowerCase();
            assert.ok(typeof(obj) === type);
        }
    }
};

// Options
vows.options = {
    emitter: process.Promise
};

// Run all vows/tests
vows.tell = function (topic, tests) {
    var promise;
    this.options.emitter.prototype.addVow = addVow;

    if (typeof topic === 'string' && tests) sys.puts('\n' + stylize(topic, 'underline') + '\n');
    else if (topic instanceof Object) tests = topic;
    else throw "tell() takes a topic and an Object";

    start = new(Date);

    for (batch in tests) {
        if (tests.hasOwnProperty(batch)) {
            promise = tests[batch].setup(this);
            for (item in tests[batch]) {
                if (tests[batch].hasOwnProperty(item) && item !== 'setup') {
                    promise.addVow(tests[batch][item], item);
                }
            }
        }
    }
    return;
};

// Return the `vows` object after setting some options
vows.config = function (opts) {
    process.mixin(this.options, opts);
    return this;
};

// Stylize a string
function stylize(str, style) {
    var styles = {
        'bold'      : [1,  22],
        'underline' : [4,  24],
        'yellow'    : [33, 39],
        'green'     : [32, 39],
        'red'       : [31, 39]
    };
    return '\033[' + styles[style][0] + 'm' + str +
           '\033[' + styles[style][1] + 'm';
}

<commit_msg>moved macros out, added BrokenVow exception<commit_after>//
// Vows.js - asynchronous promise-based testing for node.js
//
//   usage:
//
//       var vows = require('vows'),
//           assert = require('assert');
//
//       vows.tell('Deep Thought', function () {
//           question('what is the answer to the universe?').addVow(function (answer) {
//               assert.equals(answer, 42);
//           }, 'it should know the answer to the ultimate question of life');
//       });
//
require.paths.unshift('lib');

var sys = require('sys'),
    assert = require('assert'),
    inspect = require('eyes').inspector({writer: function () {}}),
    vows = exports;

// Keeps track of the outcome of vows.
var total  = 0, honored = 0,
    broken = 0, errored = 0,
    start, end;

vows.macros = {
    equal: function (actual, expected) {
        if (actual == expected) { return true  }
        else { fail("expected " + inspect(expected) + ", got " + inspect(actual)) }
    },
    match: function (actual, expected) { assert.ok(actual.match(expected)) },
    include: function (actual, item) { assert.ok(actual.match(new(RegExp)(item))) },
    beA: function (actual, type) {
        if (typeof(actual) === 'object') { assert.ok(actual.constructor === type) }
        else {
            if (typeof(type) === 'function') type = type.name.toLowerCase();
            assert.ok(typeof(actual) === type);
        }
    }
};

var BrokenVow = function (message) {
    return {
        name: 'BrokenVow',
        message: message
    };
};

function fail(message) {
    throw new(BrokenVow)(message);
}

//
// This function gets added to process.Promise.prototype, by default.
// It's essentially a wrapper around `addCallback`, which adds all the specification
// goodness.
//
function addVow(/* description & callback */) {
    var desc, callback;

    function augment(obj) {
        obj = new(obj.constructor)(obj);

        // Recursively augment any Objects
        if (obj instanceof Object) {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) obj[key] = augment(obj[key]);
            }
        }
        for (macro in vows.macros) {
            obj.should[macro] = vows.macros[macro];
        }
        return obj;
    };

    if (arguments.length < 2) throw "A vow is comprised of a description and a proof";

    total++;

    // Sometimes it might be nicer to pass the proof first,
    // and the description second, so we let the user choose
    // the order.
    if (arguments[0] instanceof Function) {
        callback = arguments[0];
        desc     = arguments[1];
    } else {
        desc     = arguments[0];
        callback = arguments[1];
    }

    return this.addCallback(function () {
        var vow = "- ", exception, topics = [], topic;

        for (var i = 0; i < arguments.length; i++) {
            topics[i] = augment(arguments[i]);
        }

        // Run the test, and try to catch `AssertionError`s and other exceptions;
        // increment counters accordingly.
        try {
            callback.apply(null, topics);
            vow += stylize(desc, 'green');
            honored++;
        } catch (e) {
            if (e.name.match(/AssertionError/)) {
                vow += stylize(desc, 'yellow');
                exception = '  ~ ' + stylize("expected " +
                    stylize(sys.inspect(e.expected), 'bold') + ", got " +
                    stylize(sys.inspect(e.actual), 'bold') + "\n", 'yellow');
                broken++;
            } else {
                vow += stylize(desc, 'red');
                exception = '  ! ' + stylize(e.stack, 'red') + "\n";
                errored++;
            }
        }
        sys.puts(vow);

        if (exception) process.stdio.writeError(exception);

        // Output results once all the vows have been checked
        if (honored + broken + errored === total) {
            var result = honored + " honored, " +
                         broken  + " broken, "  +
                         errored + " errored",

            style = honored === total ?
                ('green') : (errored === 0 ? 'yellow' : 'red');

            sys.puts("\nVerified " + total + " vows in " +
                    (((new(Date)) - start) / 1000) + " seconds.");

            sys.puts("\n" + stylize(result, style));
        }
    });
};

vows.macros = {
    equal: function (expected) { assert.equal(obj, expected) },
    match: function (expected) { assert.ok(obj.match(expected)) },
    include: function (item) { assert.ok(obj.match(new(RegExp)(item))) },
    beA: function (type) {
        if (typeof(obj) === 'object') { assert.ok(obj.constructor === type) }
        else {
            if (typeof(type) === 'function') type = type.name.toLowerCase();
            assert.ok(typeof(obj) === type);
        }
    }
};

// Options
vows.options = {
    emitter: process.Promise
};

// Run all vows/tests
vows.tell = function (topic, tests) {
    var promise;
    this.options.emitter.prototype.addVow = addVow;

    if (typeof topic === 'string' && tests) sys.puts('\n' + stylize(topic, 'underline') + '\n');
    else if (topic instanceof Object) tests = topic;
    else throw "tell() takes a topic and an Object";

    start = new(Date);

    for (batch in tests) {
        if (tests.hasOwnProperty(batch)) {
            promise = tests[batch].setup(this);
            for (item in tests[batch]) {
                if (tests[batch].hasOwnProperty(item) && item !== 'setup') {
                    promise.addVow(tests[batch][item], item);
                }
            }
        }
    }
    return;
};

// Return the `vows` object after setting some options
vows.config = function (opts) {
    process.mixin(this.options, opts);
    return this;
};

// Stylize a string
function stylize(str, style) {
    var styles = {
        'bold'      : [1,  22],
        'underline' : [4,  24],
        'yellow'    : [33, 39],
        'green'     : [32, 39],
        'red'       : [31, 39]
    };
    return '\033[' + styles[style][0] + 'm' + str +
           '\033[' + styles[style][1] + 'm';
}

<|endoftext|>