<commit_before>var path = require('path');
var url = require('url');

exports.traceurGet = function(module) {
  require('traceur');
  return $traceurRuntime.ModuleStore.get('traceur@0.0.95/src/' + module);
};

exports.extend = extend;
function extend(a, b) {
  for (var p in b)
    a[p] = b[p];
  return a;
}

exports.dextend = dextend;
function dextend(a, b) {
  for (var p in b) {
    if (!b.hasOwnProperty(p))
      continue;
    var val = b[p];
    if (typeof val === 'object')
      dextend(a[p] = typeof a[p] === 'object' ? a[p] : {}, val);
    else
      a[p] = val;
  }
  return a;
}

exports.getFormatHint = getFormatHint;
function getFormatHint(compileOpts) {
  var formatHint = '';

  if (compileOpts.format == 'amd' || compileOpts.format == 'cjs' || compileOpts.format == 'global')
    formatHint = formatHint + '"format ' + compileOpts.format + '";\n';

  if (compileOpts.format == 'global')
    for (var g in compileOpts.globalDeps)
      formatHint = formatHint + '"globals.' + compileOpts.globalDeps[g] + ' ' + g + '";\n';

  if (compileOpts.globalName)
    formatHint = formatHint + '"exports ' + compileOpts.globalName + '";\n';

  return formatHint;
}

var isWin = process.platform.match(/^win/);

exports.fromFileURL = fromFileURL;
function fromFileURL(url) {
  return url.substr(7 + !!isWin).replace(/\//g, path.sep);
}

exports.toFileURL = toFileURL;
function toFileURL(path) {
  return 'file://' + (isWin ? '/' : '') + path.replace(/\\/g, '/');
}

exports.getAlias = getAlias
function getAlias(loader, canonicalName) {
  var pluginIndex = loader.pluginFirst ? canonicalName.indexOf('!') : canonicalName.lastIndexOf('!');
  if (pluginIndex != -1)
    return getAlias(loader, canonicalName.substr(0, pluginIndex)) + '!' + getAlias(loader, canonicalName.substr(pluginIndex + 1));

  if (canonicalName.match(/\#[\:\{\?]/))
    throw new Error('Get alias not implemented for conditional name "' + canonicalName + '". Remove the conditional exclusion, or post a SystemJS Builder bug if needed!');

  var bestAlias;

  function getBestAlias(mapped) {
    return canonicalName.substr(0, mapped.length) == mapped &&
        (canonicalName.length == mapped.length || canonicalName[mapped.length] == '/');
  }

  Object.keys(loader.map).forEach(function(alias) {
    if (getBestAlias(loader.map[alias]))
      bestAlias = alias;
  });

  if (bestAlias)
    return bestAlias;

  return canonicalName;
}

exports.verifyTree = verifyTree;
function verifyTree(tree) {
  if (typeof tree != 'object' || tree instanceof Array)
    throw new TypeError('Expected a trace tree object');

  Object.keys(tree).forEach(function(key) {
    var load = tree[key];
    if (typeof load === 'boolean')
      return;
    if (load && typeof load != 'object' || !load.name || !(load.conditional || load.deps))
      throw new TypeError('Expected a trace tree object, but "' + key + '" is not a load record.');
  });
}

exports.getCanonicalName = getCanonicalName;
function getCanonicalName(loader, normalized, isPlugin) {
  // 1. Boolean conditional
  var booleanIndex = normalized.lastIndexOf('#?');
  if (booleanIndex != -1) {
    var booleanModule = normalized.substr(booleanIndex + 2);
    var negate = booleanModule[0] == '~';
    if (negate)
      booleanModule = booleanModule.substr(1);
    return getCanonicalName(loader, normalized.substr(0, booleanIndex)) + '#?' + (negate ? '~' : '') + canonicalizeCondition(loader, booleanModule);
  }

  // 2. Plugins
  var pluginIndex = loader.pluginFirst ? normalized.indexOf('!') : normalized.lastIndexOf('!');
  if (pluginIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pluginIndex), !loader.pluginFirst) + '!' + getCanonicalName(loader, normalized.substr(pluginIndex + 1), loader.pluginFirst);

  // 3. Package environment map
  var pkgEnvIndex = normalized.indexOf('/#:');
  if (pkgEnvIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pkgEnvIndex), isPlugin) + '/#:' + normalized.substr(pkgEnvIndex + 3);

  // Finally get canonical plain
  var canonical = getCanonicalNamePlain(loader, normalized, isPlugin);

  // 4. Canonicalize conditional interpolation
  var conditionalMatch = canonical.match(interpolationRegEx);
  if (conditionalMatch)
    return getCanonicalNamePlain(loader, normalized, isPlugin).replace(interpolationRegEx, '#{' + canonicalizeCondition(loader, conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)) + '}');

  return canonical;
}

// calculate the canonical name of the normalized module
// unwraps loader syntaxes to derive component parts
var interpolationRegEx = /#\{[^\}]+\}/;
function canonicalizeCondition(loader, conditionModule) {
  var conditionExport;
  var exportIndex = conditionModule.lastIndexOf('|');
  if (exportIndex != -1) {
    conditionExport = conditionModule.substr(exportIndex + 1)
    conditionModule = conditionModule.substr(0, exportIndex) || '@system-env';
  }
  return getCanonicalName(loader, conditionModule) + (conditionExport ? '|' + conditionExport : '');
}

// syntax-free getCanonicalName
// just reverse-applies paths and defulatJSExtension to determine the canonical
function getCanonicalNamePlain(loader, normalized, isPlugin) {
  // now just reverse apply paths rules to get canonical name
  var pathMatch;

  // first check exact path matches
  for (var p in loader.paths) {
    if (loader.paths[p].indexOf('*') != -1)
      continue;

    var curPath = normalizePath(loader, p, isPlugin);

    if (normalized === curPath) {
      // always stop on first exact match
      pathMatch = p;
      break;
    }
  }

  // then wildcard matches
  var pathMatchLength = 0;
  var curMatchLength;
  if (!pathMatch)
    for (var p in loader.paths) {
      if (loader.paths[p].indexOf('*') == -1)
        continue;

      // normalize the output path
      var curPath = normalizePath(loader, p, isPlugin);

      // do reverse match
      var wIndex = curPath.indexOf('*');
      if (normalized.substr(0, wIndex) === curPath.substr(0, wIndex)
        && normalized.substr(normalized.length - curPath.length + wIndex + 1) === curPath.substr(wIndex + 1)) {
        curMatchLength = curPath.split('/').length;
        if (curMatchLength >= pathMatchLength) {
          pathMatch = p.replace('*', normalized.substr(wIndex, normalized.length - curPath.length + 1));
          pathMatchLength = curMatchLength;
        }
      }
    }

  // when no path was matched, act like the standard rule is *: baseURL/*
  if (!pathMatch) {
    if (normalized.substr(0, loader.baseURL.length) == loader.baseURL)
      pathMatch = normalized.substr(loader.baseURL.length);
    else if (normalized.match(absURLRegEx))
      throw new Error('Unable to calculate canonical name to bundle ' + normalized + '. Ensure that this module sits within the baseURL or a wildcard path config.');
    else
      pathMatch = normalized;
  }

  return pathMatch;
}

exports.getPackageConfigPath = getPackageConfigPath;

// check if the given normalized name matches a packageConfigPath
// if so, loads the config
var packageConfigPaths = {};

// data object for quick checks against package paths
function createPkgConfigPathObj(path) {
  var lastWildcard = path.lastIndexOf('*');
  var length = Math.max(lastWildcard + 1, path.lastIndexOf('/'));
  return {
    length: length,
    // NB handle regex control character escapes or simply create a test function here
    regEx: new RegExp('^(' + path.substr(0, length).replace(/\*/g, '[^\\/]+') + ')(\\/|$)'),
    wildcard: lastWildcard != -1
  };
}

// most specific match wins
exports.getPackageConfigPath = getPackageConfigPath;
function getPackageConfigPath(packageConfigPaths, normalized) {
  var pkgName, exactMatch = false, configPath;
  for (var i = 0; i < packageConfigPaths.length; i++) {
    var packageConfigPath = packageConfigPaths[i];
    var p = packageConfigPaths[packageConfigPath] || (packageConfigPaths[packageConfigPath] = createPkgConfigPathObj(packageConfigPath));
    if (normalized.length < p.length)
      continue;
    var match = normalized.match(p.regEx);
    if (match && (!pkgName || (!(exactMatch && p.wildcard) && pkgName.length < match[1].length))) {
      pkgName = match[1];
      exactMatch = !p.wildcard;
      configPath = pkgName + packageConfigPath.substr(p.length);
    }
  }

  if (!pkgName)
    return;

  // return value is only part modified from SystemJS implementation of getPackageConfigMatch
  return configPath;
}

exports.getPackage = getPackage;
function getPackage(packages, name) {
  // use most specific package
  var curPkg, curPkgLen = 0, pkgLen;
  for (var p in packages) {
    if (name.substr(0, p.length) === p && (name.length === p.length || name[p.length] === '/')) {
      pkgLen = p.split('/').length;
      if (pkgLen > curPkgLen) {
        curPkg = p;
        curPkgLen = pkgLen;
      }
    }
  }
  return curPkg;
}

var absURLRegEx = /^[^\/]+:\/\//;
function normalizePath(loader, path, isPlugin) {
  var curPath;
  if (loader.paths[path][0] == '.')
    curPath = decodeURI(url.resolve(toFileURL(process.cwd()) + '/', loader.paths[path]));
  else
    curPath = decodeURI(url.resolve(loader.baseURL, loader.paths[path]));
  if (loader.defaultJSExtensions && !isPlugin && curPath.substr(curPath.length - 3, 3) != '.js')
    curPath += '.js';
  return curPath;
}

<commit_msg>remove hardcoded traceur version in utils.js<commit_after>var path = require('path');
var url = require('url');

exports.traceurGet = function(module) {
  var traceur = require('traceur');
  var traceurVersion = new traceur.loader.NodeTraceurLoader().version;
  return $traceurRuntime.ModuleStore.get('traceur@' + traceurVersion + '/src/' + module);
};

exports.extend = extend;
function extend(a, b) {
  for (var p in b)
    a[p] = b[p];
  return a;
}

exports.dextend = dextend;
function dextend(a, b) {
  for (var p in b) {
    if (!b.hasOwnProperty(p))
      continue;
    var val = b[p];
    if (typeof val === 'object')
      dextend(a[p] = typeof a[p] === 'object' ? a[p] : {}, val);
    else
      a[p] = val;
  }
  return a;
}

exports.getFormatHint = getFormatHint;
function getFormatHint(compileOpts) {
  var formatHint = '';

  if (compileOpts.format == 'amd' || compileOpts.format == 'cjs' || compileOpts.format == 'global')
    formatHint = formatHint + '"format ' + compileOpts.format + '";\n';

  if (compileOpts.format == 'global')
    for (var g in compileOpts.globalDeps)
      formatHint = formatHint + '"globals.' + compileOpts.globalDeps[g] + ' ' + g + '";\n';

  if (compileOpts.globalName)
    formatHint = formatHint + '"exports ' + compileOpts.globalName + '";\n';

  return formatHint;
}

var isWin = process.platform.match(/^win/);

exports.fromFileURL = fromFileURL;
function fromFileURL(url) {
  return url.substr(7 + !!isWin).replace(/\//g, path.sep);
}

exports.toFileURL = toFileURL;
function toFileURL(path) {
  return 'file://' + (isWin ? '/' : '') + path.replace(/\\/g, '/');
}

exports.getAlias = getAlias
function getAlias(loader, canonicalName) {
  var pluginIndex = loader.pluginFirst ? canonicalName.indexOf('!') : canonicalName.lastIndexOf('!');
  if (pluginIndex != -1)
    return getAlias(loader, canonicalName.substr(0, pluginIndex)) + '!' + getAlias(loader, canonicalName.substr(pluginIndex + 1));

  if (canonicalName.match(/\#[\:\{\?]/))
    throw new Error('Get alias not implemented for conditional name "' + canonicalName + '". Remove the conditional exclusion, or post a SystemJS Builder bug if needed!');

  var bestAlias;

  function getBestAlias(mapped) {
    return canonicalName.substr(0, mapped.length) == mapped &&
        (canonicalName.length == mapped.length || canonicalName[mapped.length] == '/');
  }

  Object.keys(loader.map).forEach(function(alias) {
    if (getBestAlias(loader.map[alias]))
      bestAlias = alias;
  });

  if (bestAlias)
    return bestAlias;

  return canonicalName;
}

exports.verifyTree = verifyTree;
function verifyTree(tree) {
  if (typeof tree != 'object' || tree instanceof Array)
    throw new TypeError('Expected a trace tree object');

  Object.keys(tree).forEach(function(key) {
    var load = tree[key];
    if (typeof load === 'boolean')
      return;
    if (load && typeof load != 'object' || !load.name || !(load.conditional || load.deps))
      throw new TypeError('Expected a trace tree object, but "' + key + '" is not a load record.');
  });
}

exports.getCanonicalName = getCanonicalName;
function getCanonicalName(loader, normalized, isPlugin) {
  // 1. Boolean conditional
  var booleanIndex = normalized.lastIndexOf('#?');
  if (booleanIndex != -1) {
    var booleanModule = normalized.substr(booleanIndex + 2);
    var negate = booleanModule[0] == '~';
    if (negate)
      booleanModule = booleanModule.substr(1);
    return getCanonicalName(loader, normalized.substr(0, booleanIndex)) + '#?' + (negate ? '~' : '') + canonicalizeCondition(loader, booleanModule);
  }

  // 2. Plugins
  var pluginIndex = loader.pluginFirst ? normalized.indexOf('!') : normalized.lastIndexOf('!');
  if (pluginIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pluginIndex), !loader.pluginFirst) + '!' + getCanonicalName(loader, normalized.substr(pluginIndex + 1), loader.pluginFirst);

  // 3. Package environment map
  var pkgEnvIndex = normalized.indexOf('/#:');
  if (pkgEnvIndex != -1)
    return getCanonicalName(loader, normalized.substr(0, pkgEnvIndex), isPlugin) + '/#:' + normalized.substr(pkgEnvIndex + 3);

  // Finally get canonical plain
  var canonical = getCanonicalNamePlain(loader, normalized, isPlugin);

  // 4. Canonicalize conditional interpolation
  var conditionalMatch = canonical.match(interpolationRegEx);
  if (conditionalMatch)
    return getCanonicalNamePlain(loader, normalized, isPlugin).replace(interpolationRegEx, '#{' + canonicalizeCondition(loader, conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)) + '}');

  return canonical;
}

// calculate the canonical name of the normalized module
// unwraps loader syntaxes to derive component parts
var interpolationRegEx = /#\{[^\}]+\}/;
function canonicalizeCondition(loader, conditionModule) {
  var conditionExport;
  var exportIndex = conditionModule.lastIndexOf('|');
  if (exportIndex != -1) {
    conditionExport = conditionModule.substr(exportIndex + 1)
    conditionModule = conditionModule.substr(0, exportIndex) || '@system-env';
  }
  return getCanonicalName(loader, conditionModule) + (conditionExport ? '|' + conditionExport : '');
}

// syntax-free getCanonicalName
// just reverse-applies paths and defulatJSExtension to determine the canonical
function getCanonicalNamePlain(loader, normalized, isPlugin) {
  // now just reverse apply paths rules to get canonical name
  var pathMatch;

  // first check exact path matches
  for (var p in loader.paths) {
    if (loader.paths[p].indexOf('*') != -1)
      continue;

    var curPath = normalizePath(loader, p, isPlugin);

    if (normalized === curPath) {
      // always stop on first exact match
      pathMatch = p;
      break;
    }
  }

  // then wildcard matches
  var pathMatchLength = 0;
  var curMatchLength;
  if (!pathMatch)
    for (var p in loader.paths) {
      if (loader.paths[p].indexOf('*') == -1)
        continue;

      // normalize the output path
      var curPath = normalizePath(loader, p, isPlugin);

      // do reverse match
      var wIndex = curPath.indexOf('*');
      if (normalized.substr(0, wIndex) === curPath.substr(0, wIndex)
        && normalized.substr(normalized.length - curPath.length + wIndex + 1) === curPath.substr(wIndex + 1)) {
        curMatchLength = curPath.split('/').length;
        if (curMatchLength >= pathMatchLength) {
          pathMatch = p.replace('*', normalized.substr(wIndex, normalized.length - curPath.length + 1));
          pathMatchLength = curMatchLength;
        }
      }
    }

  // when no path was matched, act like the standard rule is *: baseURL/*
  if (!pathMatch) {
    if (normalized.substr(0, loader.baseURL.length) == loader.baseURL)
      pathMatch = normalized.substr(loader.baseURL.length);
    else if (normalized.match(absURLRegEx))
      throw new Error('Unable to calculate canonical name to bundle ' + normalized + '. Ensure that this module sits within the baseURL or a wildcard path config.');
    else
      pathMatch = normalized;
  }

  return pathMatch;
}

exports.getPackageConfigPath = getPackageConfigPath;

// check if the given normalized name matches a packageConfigPath
// if so, loads the config
var packageConfigPaths = {};

// data object for quick checks against package paths
function createPkgConfigPathObj(path) {
  var lastWildcard = path.lastIndexOf('*');
  var length = Math.max(lastWildcard + 1, path.lastIndexOf('/'));
  return {
    length: length,
    // NB handle regex control character escapes or simply create a test function here
    regEx: new RegExp('^(' + path.substr(0, length).replace(/\*/g, '[^\\/]+') + ')(\\/|$)'),
    wildcard: lastWildcard != -1
  };
}

// most specific match wins
exports.getPackageConfigPath = getPackageConfigPath;
function getPackageConfigPath(packageConfigPaths, normalized) {
  var pkgName, exactMatch = false, configPath;
  for (var i = 0; i < packageConfigPaths.length; i++) {
    var packageConfigPath = packageConfigPaths[i];
    var p = packageConfigPaths[packageConfigPath] || (packageConfigPaths[packageConfigPath] = createPkgConfigPathObj(packageConfigPath));
    if (normalized.length < p.length)
      continue;
    var match = normalized.match(p.regEx);
    if (match && (!pkgName || (!(exactMatch && p.wildcard) && pkgName.length < match[1].length))) {
      pkgName = match[1];
      exactMatch = !p.wildcard;
      configPath = pkgName + packageConfigPath.substr(p.length);
    }
  }

  if (!pkgName)
    return;

  // return value is only part modified from SystemJS implementation of getPackageConfigMatch
  return configPath;
}

exports.getPackage = getPackage;
function getPackage(packages, name) {
  // use most specific package
  var curPkg, curPkgLen = 0, pkgLen;
  for (var p in packages) {
    if (name.substr(0, p.length) === p && (name.length === p.length || name[p.length] === '/')) {
      pkgLen = p.split('/').length;
      if (pkgLen > curPkgLen) {
        curPkg = p;
        curPkgLen = pkgLen;
      }
    }
  }
  return curPkg;
}

var absURLRegEx = /^[^\/]+:\/\//;
function normalizePath(loader, path, isPlugin) {
  var curPath;
  if (loader.paths[path][0] == '.')
    curPath = decodeURI(url.resolve(toFileURL(process.cwd()) + '/', loader.paths[path]));
  else
    curPath = decodeURI(url.resolve(loader.baseURL, loader.paths[path]));
  if (loader.defaultJSExtensions && !isPlugin && curPath.substr(curPath.length - 3, 3) != '.js')
    curPath += '.js';
  return curPath;
}

<|endoftext|>


<commit_before>var isArray = (Array.hasOwnProperty('isArray')) ? Array.isArray : function (obj) {
  return (obj) ? (typeof obj === 'object' && Object.prototype.toString.call(obj).indexOf() !== -1) : false;
};

exports.strip = function (input) {
  return input.replace(/^\s+|\s+$/g, '');
};

exports.startsWith = function (str, prefix) {
  return str.indexOf(prefix) === 0;
};

exports.endsWith = function (str, suffix) {
  return str.indexOf(suffix, str.length - suffix.length) !== -1;
};

exports.each = function (obj, fn) {
  var i, l;

  if (isArray(obj)) {
    i = 0;
    l = obj.length;
    for (i; i < l; i += 1) {
      if (fn(obj[i], i, obj) === false) {
        break;
      }
    }
  } else {
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        if (fn(obj[i], i, obj) === false) {
          break;
        }
      }
    }
  }

  return obj;
};

exports.isArray = isArray;

exports.some = function (obj, fn) {
  var i = 0,
    result,
    l;
  if (isArray(obj)) {
    l = obj.length;

    for (i; i < l; i += 1) {
      result = fn(obj[i], i, obj);
      if (result) {
        break;
      }
    }
  } else {
    exports.each(obj, function (value, index, collection) {
      result = fn(value, index, obj);
      return !(result);
    });
  }
  return !!result;
};

exports.map = function (obj, fn) {
  var i = 0,
    result,
    l;

  if (isArray(obj)) {
    result = [];
    l = obj.length;
    for (i; i < l; i += 1) {
      result[i] = fn(obj[i], i);
    }
  } else {
    result = [];
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        result[i] = fn(obj[i], i);
      }
    }
  }
  return result;
};

exports.extend = function () {
  var args = arguments,
    target = args[0],
    objs = (args.length > 1) ? Array.prototype.slice.call(args, 1) : [],
    i = 0,
    l = objs.length,
    key,
    obj;

  for (i; i < l; i += 1) {
    obj = objs[i] || {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        target[key] = obj[key];
      }
    }
  }
  return target;
};
<commit_msg>jsdoc utils.js<commit_after>var isArray = (Array.hasOwnProperty('isArray')) ? Array.isArray : function (obj) {
  return (obj) ? (typeof obj === 'object' && Object.prototype.toString.call(obj).indexOf() !== -1) : false;
};

/**
 * Strip leading and trailing whitespace from a string.
 * @param  {string} input
 * @return {string}       Stripped input.
 */
exports.strip = function (input) {
  return input.replace(/^\s+|\s+$/g, '');
};

/**
 * Test if a string starts with a given prefix.
 * @param  {string} str    String to test against.
 * @param  {string} prefix Prefix to check for.
 * @return {boolean}
 */
exports.startsWith = function (str, prefix) {
  return str.indexOf(prefix) === 0;
};

/**
 * Test if a string ends with a given suffix.
 * @param  {string} str    String to test against.
 * @param  {string} suffix Suffix to check for.
 * @return {boolean}
 */
exports.endsWith = function (str, suffix) {
  return str.indexOf(suffix, str.length - suffix.length) !== -1;
};

/**
 * Iterate over an array or object.
 * @param  {array|object} obj Enumerable object.
 * @param  {Function}     fn  Callback function executed for each item.
 * @return {array|object}     The original input object.
 */
exports.each = function (obj, fn) {
  var i, l;

  if (isArray(obj)) {
    i = 0;
    l = obj.length;
    for (i; i < l; i += 1) {
      if (fn(obj[i], i, obj) === false) {
        break;
      }
    }
  } else {
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        if (fn(obj[i], i, obj) === false) {
          break;
        }
      }
    }
  }

  return obj;
};

/**
 * Test if an object is an Array.
 * @param {object} obj
 * @return {boolean}
 */
exports.isArray = isArray;

/**
 * Test if an item in an enumerable matches your conditions.
 * @param  {array|object}   obj   Enumerable object.
 * @param  {Function}       fn    Executed for each item. Return true if your condition is met.
 * @return {boolean}
 */
exports.some = function (obj, fn) {
  var i = 0,
    result,
    l;
  if (isArray(obj)) {
    l = obj.length;

    for (i; i < l; i += 1) {
      result = fn(obj[i], i, obj);
      if (result) {
        break;
      }
    }
  } else {
    exports.each(obj, function (value, index, collection) {
      result = fn(value, index, obj);
      return !(result);
    });
  }
  return !!result;
};

/**
 * Return a new enumerable, mapped by a given iteration function.
 * @param  {object}   obj Enumerable object.
 * @param  {Function} fn  Executed for each item. Return the item to replace the original item with.
 * @return {object}       New mapped object.
 */
exports.map = function (obj, fn) {
  var i = 0,
    result,
    l;

  if (isArray(obj)) {
    result = [];
    l = obj.length;
    for (i; i < l; i += 1) {
      result[i] = fn(obj[i], i);
    }
  } else {
    result = [];
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        result[i] = fn(obj[i], i);
      }
    }
  }
  return result;
};

/**
 * Copy all of the properties in the source objects over to the destination object, and return the destination object. It's in-order, so the last source will override properties of the same name in previous arguments.
 * @param {...object} arguments
 * @return {object}
 */
exports.extend = function () {
  var args = arguments,
    target = args[0],
    objs = (args.length > 1) ? Array.prototype.slice.call(args, 1) : [],
    i = 0,
    l = objs.length,
    key,
    obj;

  for (i; i < l; i += 1) {
    obj = objs[i] || {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        target[key] = obj[key];
      }
    }
  }
  return target;
};
<|endoftext|>


<commit_before>var CreateHash = require('crypto').createHash;

exports.validateArg = function validateArg(args, config){
  var toString = Object.prototype.toString
    , err
    , callback;

  args.validate.forEach(function(tokens){
    var key = tokens[0]
      , value = args[key];

    switch(tokens[1]){
      case Number:
        if (toString.call(value) !== '[object Number]') err = 'Argument "' + key + '" is not a valid Number.';
        break;

      case Boolean:
        if (toString.call(value) !== '[object Boolean]') err = 'Argument "' + key + '" is not a valid Boolean.';
        break;

      case Array:
        if (toString.call(value) !== '[object Array]') err = 'Argument "' + key + '" is not a valid Array.';
        break;

      case Object:
        if (toString.call(value) !== '[object Object]') err = 'Argument "' + key + '" is not a valid Object.';
        break;

      case Function:
        if (toString.call(value) !== '[object Function]') err = 'Argument "' + key + '" is not a valid Function.';
        break;

      case String:
        if (toString.call(value) !== '[object String]') err = 'Argument "' + key + '" is not a valid String.';

        if (!err && key == 'key' && value.length > config.maxKeySize){
          if (config.keyCompression){
            args[key] = CreateHash('md5').update(value).digest('hex');

            // also make sure you update the command
            args.command.replace(new RegExp('^(' + value + ')'), args[key]);
          } else {
            err = 'Argument "' + key + '" is longer than the maximum allowed length of ' + config.maxKeySize;
          }
        }

        break;

      default:
        if (toString.call(value) == '[object global]' && !tokens[2]) err = 'Argument "' + key + '" is not defined.';
    }
  });

  if (err){
    if(callback) callback(err, false);
    return false;
  }

  return true;
};

// currys a function
exports.curry = function curry(context, func){
  var copy = Array.prototype.slice
    , args = copy.call(arguments, 2);

  return function(){
    return func.apply(context || this, args.concat(copy.call(arguments)));
  }
};

// a small util to use an object for eventEmitter
exports.fuse = function fuse(target, handlers){
  for(var i in handlers)
    if (handlers.hasOwnProperty(i)){
      target.on(i, handlers[i]);
    }
};

// merges a object's proppertys / values with a other object
exports.merge = function merge(target, obj){
  for(var i in obj){
    target[i] = obj[i];
  }

  return target;
};

// a small items iterator
exports.Iterator = function iterator(collection, callback){
  var arr = Array.isArray(collection)
    , keys = !arr ? Object.keys(collection) : false
    , index = 0
    , maximum = arr ? collection.length : keys.length
    , self = this;

  // returns next item
  this.next = function(){
    var obj = arr ? collection[index] : { key: keys[index], value: collection[keys[index]] };
    callback(obj, index++, collection, self);
  };

  // check if we have more items
  this.hasNext = function(){
    return index < maximum;
  };
};<commit_msg>Additional fix for the to-long key issue<commit_after>"use strict";

var createHash = require('crypto').createHash;

exports.validateArg = function validateArg(args, config){
  var toString = Object.prototype.toString
    , err
    , callback;

  args.validate.forEach(function(tokens){
    var key = tokens[0]
      , value = args[key];

    switch(tokens[1]){
      case Number:
        if (toString.call(value) !== '[object Number]') err = 'Argument "' + key + '" is not a valid Number.';
        break;

      case Boolean:
        if (toString.call(value) !== '[object Boolean]') err = 'Argument "' + key + '" is not a valid Boolean.';
        break;

      case Array:
        if (toString.call(value) !== '[object Array]') err = 'Argument "' + key + '" is not a valid Array.';
        break;

      case Object:
        if (toString.call(value) !== '[object Object]') err = 'Argument "' + key + '" is not a valid Object.';
        break;

      case Function:
        if (toString.call(value) !== '[object Function]') err = 'Argument "' + key + '" is not a valid Function.';
        break;

      case String:
        if (toString.call(value) !== '[object String]') err = 'Argument "' + key + '" is not a valid String.';

        if (!err && key === 'key' && value.length > config.maxKeySize){
          if (config.keyCompression){
            args[key] = createHash('md5').update(value).digest('hex');

            // also make sure you update the command
            args.command.replace(value, args[key]);
          } else {
            err = 'Argument "' + key + '" is longer than the maximum allowed length of ' + config.maxKeySize;
          }
        }

        break;

      default:
        if (toString.call(value) === '[object global]' && !tokens[2]) err = 'Argument "' + key + '" is not defined.';
    }
  });

  if (err){
    if(callback) callback(err, false);
    return false;
  }

  return true;
};

// currys a function
exports.curry = function curry (context, func) {
  var copy = Array.prototype.slice
    , args = copy.call(arguments, 2);

  return function () {
    return func.apply(context || this, args.concat(copy.call(arguments)));
  };
};

// a small util to use an object for eventEmitter
exports.fuse = function fuse (target, handlers) {
  for(var i in handlers)
    if (handlers.hasOwnProperty(i)){
      target.on(i, handlers[i]);
    }
};

// merges a object's proppertys / values with a other object
exports.merge = function merge (target, obj) {
  for (var i in obj) {
    target[i] = obj[i];
  }

  return target;
};

// a small items iterator
exports.Iterator = function iterator (collection, callback) {
  var arr = Array.isArray(collection)
    , keys = !arr ? Object.keys(collection) : false
    , index = 0
    , maximum = arr ? collection.length : keys.length
    , self = this;

  // returns next item
  this.next = function next () {
    var obj = arr ? collection[index] : { key: keys[index], value: collection[keys[index]] };
    callback(obj, index++, collection, self);
  };

  // check if we have more items
  this.hasNext = function hasNext () {
    return index < maximum;
  };
};
<|endoftext|>


<commit_before>const debug = require('debug')('wechat');
const crypto = require("crypto");
const request = require('request-promise');
const Promise = require('bluebird');
const config = require('./config');

const defaultOptions = {
  baseUrl: config.getDefaultConfiguration().apiUrl,
  json: true,
  strictSSL: false,
  simple: true,
  resolveWithFullResponse: false,
};

const util = {};

util.genHash = (text, algorithm = 'sha1') => {
  const c = crypto.createHash(algorithm);
  c.update(text);
  return c.digest("hex");
};

util.genSHA1 = text => util.genHash(text, "sha1");

util.paramsToString = (args) => {
  let keys = Object.keys(args);
  keys = keys.sort();
  const newArgs = {};
  keys.forEach((key) => {
    newArgs[key.toLowerCase()] = args[key];
  });

  let str = '';
  for (let k in newArgs) {
    if(newArgs.hasOwnProperty(k)) {
      str += '&' + k + '=' + newArgs[k];
    }
  }
  str = str.substr(1);
  return str;
};

util.sendWechatRequest = (options) => {
  const myOptions = Object.assign({}, defaultOptions, options);
  return request(myOptions)
    .then((body) => {
      if(body.hasOwnProperty('errcode') && body.errcode != 0) {
        debug(body);
      }
      return Promise.resolve(body);
    })
    .catch((err) => {
      debug(err);
      return Promise.reject(err);
    });
};

module.exports = util;<commit_msg>add jsdoc for utils<commit_after>const debug = require('debug')('wechat');
const crypto = require('crypto');
const request = require('request-promise');
const Promise = require('bluebird');
const config = require('./config');

const defaultOptions = {
  baseUrl: config.getDefaultConfiguration().apiUrl,
  json: true,
  strictSSL: false,
  simple: true,
  resolveWithFullResponse: false,
};

const util = {};

/**
 * Generate digest hash based on the content
 * @param {*} content content to be digested
 * @param {string=} algorithm digest algorithm, default 'sha1'
 * @return {string}
 */
util.genHash = (content, algorithm = 'sha1') => {
  const c = crypto.createHash(algorithm);
  c.update(text);
  return c.digest('hex');
};

/**
 * Generate sha1 content
 * @param {*} content
 * @return {string}
 */
util.genSHA1 = content => util.genHash(content, 'sha1');

/**
 * Parse the object to query string without encoding based on the ascii key order
 * @param {object} args
 * @return {string}
 */
util.paramsToString = (args) => {
  let keys = Object.keys(args);
  keys = keys.sort();
  const newArgs = {};
  keys.forEach((key) => {
    newArgs[key.toLowerCase()] = args[key];
  });

  let str = '';
  for (let k in newArgs) {
    if(newArgs.hasOwnProperty(k)) {
      str += '&' + k + '=' + newArgs[k];
    }
  }
  str = str.substr(1);
  return str;
};

/**
 * Send the request to wechat server
 * @param {object} options custom request options
 * @return {Promise}
 */
util.sendWechatRequest = (options) => {
  const myOptions = Object.assign({}, defaultOptions, options);
  return request(myOptions)
    .then((body) => {
      if(body.hasOwnProperty('errcode') && body.errcode != 0) {
        debug(body);
      }
      return Promise.resolve(body);
    })
    .catch((err) => {
      debug(err);
      return Promise.reject(err);
    });
};

module.exports = util;<|endoftext|>


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

exports.isKey = function(obj) {
  if (toString.call(obj) === '[object String]') {
    if (obj === 'master') {
      return true;
    }

    if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(obj)) {
      return true;
    }
  }
  return false;
};

exports.isPacket = function(obj) {
  if (toString.call(obj) !== '[object Object]' || Object.keys(obj).length < 2) {
    return false;
  }

  if (toString.call(obj.things) !== '[object String]') {
    if (!Array.isArray(obj.things) || obj.things.length < 1) {
      return false;
    }
  }

  if (toString.call(obj.payload) !== '[object Object]') {
    return false;
  }
  return true;
};<commit_msg>Adding a errors handler for mongoose<commit_after>var util = require('util')
  , _ = require('underscore')._;

var messages = {
  'enum': '%s not an allowed value',
  'required': '%s is required',
  'min': '%s below minimum',
  'max': '%s above maximum'
};

exports.handleError = function(err, fn) {
  var errors = {};

  if (err.name !== 'ValidationError') {
    fn({
      message: 'Something went wrong',
      code: 500
    });
    return;
  }

  _.each(err.errors, function(v, k) {
    if (!messages.hasOwnProperty(v.type)) {
      errors[k] = v.type;
      return;
    }

    errors[k] = util.format(
      messages[v.type],
      v.path
    );
  });

  fn({
    message: 'Validation failed',
    code: 400,
    errors: errors
  });
};

exports.isKey = function(obj) {
  if (toString.call(obj) === '[object String]') {
    if (obj === 'master') {
      return true;
    }

    if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(obj)) {
      return true;
    }
  }
  return false;
};

exports.isPacket = function(obj) {
  if (toString.call(obj) !== '[object Object]' || Object.keys(obj).length < 2) {
    return false;
  }

  if (toString.call(obj.things) !== '[object String]') {
    if (!Array.isArray(obj.things) || obj.things.length < 1) {
      return false;
    }
  }

  if (toString.call(obj.payload) !== '[object Object]') {
    return false;
  }
  return true;
};<|endoftext|>


<commit_before>var controllerDir;
var appName;

function getAppName() {
    var parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

// Get js-controller directory to load libs
function getControllerDir(isInstall) {
    var fs = require('fs');
    // Find the js-controller location
    var controllerDir = __dirname.replace(/\\/g, '/');
    controllerDir = controllerDir.split('/');
    if (controllerDir[controllerDir.length - 3] === 'adapter') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
    } else if (controllerDir[controllerDir.length - 3] === 'node_modules') {
        controllerDir.splice(controllerDir.length - 3, 3);
        controllerDir = controllerDir.join('/');
        if (fs.existsSync(controllerDir + '/node_modules/' + appName + '.js-controller')) {
            controllerDir += '/node_modules/' + appName + '.js-controller';
        } else if (fs.existsSync(controllerDir + '/node_modules/' + appName.toLowerCase() + '.js-controller')) {
            controllerDir += '/node_modules/' + appName.toLowerCase() + '.js-controller';
        } else if (!fs.existsSync(controllerDir + '/controller.js')) {
            if (!isInstall) {
                console.log('Cannot find js-controller');
                process.exit(10);
            } else {
                process.exit();
            }
        }
    } else if (fs.existsSync(__dirname + '/../../node_modules/' + appName.toLowerCase() + '.js-controller')) {
        controllerDir.splice(controllerDir.length - 2, 2);
        return controllerDir.join('/') + '/node_modules/' + appName.toLowerCase() + '.js-controller';
    } else {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    return controllerDir;
}

// Read controller configuration file
function getConfig() {
    var fs = require('fs');
    if (fs.existsSync(controllerDir + '/conf/' + appName + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName + '.json'));
    } else if (fs.existsSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json')) {
        return JSON.parse(fs.readFileSync(controllerDir + '/conf/' + appName.toLowerCase() + '.json'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.Adapter =       require(controllerDir + '/lib/adapter.js');
exports.appName =       appName;
<commit_msg>update utils.js<commit_after>'use strict';

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

let controllerDir;
let appName;

/**
 * returns application name
 *
 * The name of the application can be different and this function finds it out.
 *
 * @returns {string}
 */
 function getAppName() {
    const parts = __dirname.replace(/\\/g, '/').split('/');
    return parts[parts.length - 2].split('.')[0];
}

/**
 * looks for js-controller home folder
 *
 * @param {boolean} isInstall
 * @returns {string}
 */
function getControllerDir(isInstall) {
    // Find the js-controller location
    const possibilities = [
        'iobroker.js-controller',
        'ioBroker.js-controller',
    ];
    /** @type {string} */
    let controllerPath;
    for (const pkg of possibilities) {
        try {
            const possiblePath = require.resolve(pkg);
            if (fs.existsSync(possiblePath)) {
                controllerPath = possiblePath;
                break;
            }
        } catch (e) { /* not found */ }
    }
    if (controllerPath == null) {
        if (!isInstall) {
            console.log('Cannot find js-controller');
            process.exit(10);
        } else {
            process.exit();
        }
    }
    // we found the controller
    return path.dirname(controllerPath);
}

/**
 * reads controller base settings
 *
 * @alias getConfig
 * @returns {object}
 */
 function getConfig() {
    let configPath;
    if (fs.existsSync(
        configPath = path.join(controllerDir, 'conf', appName + '.json')
    )) {
        return JSON.parse(fs.readFileSync(configPath, 'utf8'));
    } else if (fs.existsSync(
        configPath = path.join(controllerDir, 'conf', + appName.toLowerCase() + '.json')
    )) {
        return JSON.parse(fs.readFileSync(configPath, 'utf8'));
    } else {
        throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
    }
}
appName       = getAppName();
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
const adapter = require(path.join(controllerDir, 'lib/adapter.js'));

exports.controllerDir = controllerDir;
exports.getConfig =     getConfig;
exports.Adapter =       adapter;
exports.appName =       appName;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');

var _ = require('underscore');
var Promise = require('es6-promise').Promise;
require('shelljs/global');

var log = require('./log');

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

var blockRX = new RegExp('^/\\* START FFOS-PROXY.*?\\*/\\n' +
                         '([\\s\\S]*?)' +
                         '\\n/\\* END FFOS-PROXY.*?\\*/$', 'm');

if (typeof String.prototype.endsWith !== 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

function trimBrackets(input) {
  return input.replace(/ \(.*?\)/, '').trim();
}

function handleError(err) {
  if (global.debug === true) {
    console.error(err.stack);
  } else {
    log.error(err.toString());
  }
}

function getCertsList(certDir) {
  var files = fs.readdirSync(certDir);
  var certsList = [];
  for (var i=0; i < files.length; i++) {
    var file = files[i];
    if (file.endsWith('.pem')) {
      certsList.push(file);
    }
  }
  return certsList;
}

function extractProxyBlock(haystack) {
  return blockRX.exec(haystack);
}

function hasProxyBlock(haystack) {
  return extractProxyBlock(haystack) !== null;
}

function templateProxyBlock(templateString, context) {
  var template = _.template(templateString);
  return template(context);
}

function replaceProxyBlock(input, replacement) {
  return input.replace(blockRX, replacement);
}

function containsProxyConf(input) {
  return /network\.proxy/.exec(input);
}

function detectLegacyConf(input) {
  if (!hasProxyBlock(input) && containsProxyConf(input)) {
    throw Error('Refusing to process user.js with existing proxy conf');
  }
}

function collapseHomeDir(path, home) {
  home = home || process.env.HOME;
  home = home.replace(/\/$/, '');
  var newPath = path.replace(home + '/', '~/');
  return newPath === '~/' ? '~' : newPath;
}

function copyFile(source, target) {
  return new Promise(function(resolve, reject) {
    var rd = fs.createReadStream(source);
    var wr = fs.createWriteStream(target);
    rd.on('error', function(err) {
      reject(err);
    });
    wr.on('error', function(err) {
      reject(err);
    });
    wr.on('close', function() {
      resolve();
    });
    rd.pipe(wr);
  });
}

function hasCertutilCmd() {
  var certutilPath = which('certutil');
  if (!certutilPath) {
    throw new Error('Certuil needs to be installed see ' +
      'https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS');
  } else {
    return certutilPath;
  }
}

module.exports = {
  collapseHomeDir: collapseHomeDir,
  containsProxyConf: containsProxyConf,
  copyFile: copyFile,
  detectLegacyConf: detectLegacyConf,
  extractProxyBlock: extractProxyBlock,
  getCertsList: getCertsList,
  handleError: handleError,
  hasCertutilCmd: hasCertutilCmd,
  hasProxyBlock: hasProxyBlock,
  replaceProxyBlock: replaceProxyBlock,
  templateProxyBlock: templateProxyBlock,
  trimBrackets: trimBrackets,
};

<commit_msg>Handle no cert in certDir<commit_after>'use strict';

var fs = require('fs');

var _ = require('underscore');
var Promise = require('es6-promise').Promise;
require('shelljs/global');

var log = require('./log');

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

var blockRX = new RegExp('^/\\* START FFOS-PROXY.*?\\*/\\n' +
                         '([\\s\\S]*?)' +
                         '\\n/\\* END FFOS-PROXY.*?\\*/$', 'm');

if (typeof String.prototype.endsWith !== 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

function trimBrackets(input) {
  return input.replace(/ \(.*?\)/, '').trim();
}

function handleError(err) {
  if (global.debug === true) {
    console.error(err.stack);
  } else {
    log.error(err.toString());
  }
}

function getCertsList(certDir) {
  var files = fs.readdirSync(certDir);
  var certsList = [];
  for (var i=0; i < files.length; i++) {
    var file = files[i];
    if (file.endsWith('.pem')) {
      certsList.push(file);
    }
  }
  if (!certsList.length) {
    throw new Error('No certs found. Try adding a cert to the certDir');
  }
  return certsList;
}

function extractProxyBlock(haystack) {
  return blockRX.exec(haystack);
}

function hasProxyBlock(haystack) {
  return extractProxyBlock(haystack) !== null;
}

function templateProxyBlock(templateString, context) {
  var template = _.template(templateString);
  return template(context);
}

function replaceProxyBlock(input, replacement) {
  return input.replace(blockRX, replacement);
}

function containsProxyConf(input) {
  return /network\.proxy/.exec(input);
}

function detectLegacyConf(input) {
  if (!hasProxyBlock(input) && containsProxyConf(input)) {
    throw Error('Refusing to process user.js with existing proxy conf');
  }
}

function collapseHomeDir(path, home) {
  home = home || process.env.HOME;
  home = home.replace(/\/$/, '');
  var newPath = path.replace(home + '/', '~/');
  return newPath === '~/' ? '~' : newPath;
}

function copyFile(source, target) {
  return new Promise(function(resolve, reject) {
    var rd = fs.createReadStream(source);
    var wr = fs.createWriteStream(target);
    rd.on('error', function(err) {
      reject(err);
    });
    wr.on('error', function(err) {
      reject(err);
    });
    wr.on('close', function() {
      resolve();
    });
    rd.pipe(wr);
  });
}

function hasCertutilCmd() {
  var certutilPath = which('certutil');
  if (!certutilPath) {
    throw new Error('Certuil needs to be installed see ' +
      'https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS');
  } else {
    return certutilPath;
  }
}

module.exports = {
  collapseHomeDir: collapseHomeDir,
  containsProxyConf: containsProxyConf,
  copyFile: copyFile,
  detectLegacyConf: detectLegacyConf,
  extractProxyBlock: extractProxyBlock,
  getCertsList: getCertsList,
  handleError: handleError,
  hasCertutilCmd: hasCertutilCmd,
  hasProxyBlock: hasProxyBlock,
  replaceProxyBlock: replaceProxyBlock,
  templateProxyBlock: templateProxyBlock,
  trimBrackets: trimBrackets,
};

<|endoftext|>


<commit_before>/* Utility functions for noylitics */
var sys = require('sys');

var utils = exports;
// create a bind wrapper to keep scope.
utils.bind = function (object, method) {
    return function() {
	return method.apply(object, arguments);
    };
};

// match  all urls and return a list
utils.urlMatch = function (data) {
  var url_pattern = /https?:\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?/gi;
  return data.match(url_pattern) || [];

};

utils.parseRate = function (data) {
  var rate_pattern = new RegExp("rate ([a-zA-Z0-9#]+) (\d+)*", "gi");

  return data.match(rate_pattern) || [];

};<commit_msg>small change in rate utils<commit_after>/* Utility functions for noylitics */
var sys = require('sys');

var utils = exports;
// create a bind wrapper to keep scope.
utils.bind = function (object, method) {
    return function() {
	return method.apply(object, arguments);
    };
};

// match  all urls and return a list
utils.urlMatch = function (data) {
  var url_pattern = /https?:\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?/gi;
  return data.match(url_pattern) || [];

};

utils.parseRate = function (data) {
  var rate_pattern = /rate ([a-zA-Z0-9#]+) (\d+)/gi;

  return data.match(rate_pattern) || [];

};<|endoftext|>


<commit_before>'use strict';

var isPlainObject = require('lodash/lang/isPlainObject')
	, path = require('path')

	, ATTRIBUTE_BLACKLIST = ['href', 'rel', 'src']
	, RE_ESCAPE = /[-\/\\^$*+?.()|[\]{}]/g
		// Multiline, tags
	, RE_NOT_FILEPATH = /[\r\n<>]/gm;

/**
 * Determine if 'str' is likely a filepath
 * @param {String} str
 * @returns {Boolean}
 */
exports.isFilepath = function (str) {
	RE_NOT_FILEPATH.lastIndex = 0;
	if (str) return !RE_NOT_FILEPATH.test(str);
	return false;
};

/**
 * Retrieve tag regexp for 'attribute'
 * @param {String} attribute
 * @returns {RegExp}
 */
exports.getTagRegExp = function (attribute) {
	return new RegExp('<([a-zA-Z]+)\\b[\\sa-zA-Z=\'"\\-/._+]*?\\s' + attribute + '\\b[^>]*?>(?:<\\/\\1\\s?>)?', 'gm');
};

/**
 * Parse 'attributes'
 * @param {Object} attributes
 * @returns {Object}
 */
exports.parseAttributes = function (attributes) {
	for (var prop in attributes) {
		// Parse boolean values
		if (attributes[prop] === '') attributes[prop] = true;
	}

	return attributes;
};

/**
 * Parse props with 'prefix' from 'attributes'
 * @param {Object} attributes
 * @param {String} prefix
 * @returns {Object}
 */
exports.parseProps = function (attributes, prefix) {
	prefix += '-';

	var props = {};

	for (var prop in attributes) {
		// Strip 'inline-' and store
		if (prop.indexOf(prefix) == 0) {
			props[prop.slice(prefix.length)] = attributes[prop];
		}
	}

	return props;
};

/**
 * Retrieve resolved 'filepath'
 * @param {String} filepath
 * @param {String} htmlpath
 * @param {String} rootpath
 * @returns {String}
 */
exports.getSourcepath = function (filepath, htmlpath, rootpath) {
	if (filepath) {
		if (htmlpath && filepath.indexOf('./') == 0 || filepath.indexOf('../') == 0) {
			return path.resolve(path.dirname(htmlpath), filepath);
		} else {
			// Strip leading '/'
			if (filepath.indexOf('/') == 0) filepath = filepath.slice(1);
			return path.resolve(rootpath, filepath);
		}
	}

	return '';
};

/**
 * Retrieve type based on 'type'
 * @param {String} tag
 * @returns {String}
 */
exports.getTypeFromType = function (type) {
	if (type) {
		switch (type) {
			case 'application/javascript':
			case 'application/x-javascript':
			case 'application/ecmascript':
			case 'text/javascript':
			case 'text/ecmascript':
			case 'javascript':
			case 'js':
			case 'ecmascript':
				return 'js';
			case 'text/css':
			case 'css':
				return 'css';
			case 'image/png':
			case 'image/gif':
			case 'image/jpeg':
			case 'image/jpg':
			case 'image/svg+xml':
			case 'image/svg':
			case 'png':
			case 'gif':
			case 'jpeg':
			case 'jpg':
			case 'svg':
			case 'image':
				return 'image';
			case 'application/json':
			case 'text/json':
			case 'json':
				return 'json';
			default:
				return type;
		}
	}
};

/**
 * Retrieve type based on 'tag'
 * @param {String} tag
 * @returns {String}
 */
exports.getTypeFromTag = function (tag) {
	if (tag) {
		switch (tag) {
			case 'script':
				return 'js';
			case 'link':
				return 'css';
			case 'img':
				return 'image';
			default:
				return '';
		}
	}
};

/**
 * Retrieve format based on 'extension'
 * @param {String} extension
 * @returns {String}
 */
exports.getFormatFromExtension = function (extension) {
	if (extension) {
		switch (extension) {
			case 'js':
				return 'js';
			case 'json':
				return 'json';
			case 'css':
				return 'css';
			case 'gif':
				return 'gif';
			case 'png':
				return 'png';
			case 'jpeg':
			case 'jpg':
				return 'jpeg';
			case 'svg':
				return 'svg+xml';
			default:
				return extension;
		}
	}
};

/**
 * Retrieve leading whitespace for 'source' in 'html'
 * @param {String} source
 * @param {String} html
 * @returns {String}
 */
exports.getPadding = function (source, html) {
	var re = new RegExp('^([\\t ]+)' + exports.escape(source), 'gm')
		, match = re.exec(html);

	return match ? match[1] : '';
};

/**
 * Retrieve stringified attributes
 * @param {Object} attributes
 * @param {String} prefix
 * @param {Boolean} strict
 * @returns {String}
 */
exports.getAttributeString = function (attributes, prefix, strict) {
	var str = '';

	for (var prop in attributes) {
		// Ignore blacklisted and prefixed attributes
		var include = strict
			? prop.indexOf(prefix) != 0 && !~ATTRIBUTE_BLACKLIST.indexOf(prop)
			: prop.indexOf(prefix) != 0;

		if (include) {
			str += (attributes[prop] === true)
				? ' ' + prop
				: ' ' + prop + '="' + attributes[prop] + '"';
		}
	}

	return str;
};

/**
 * Retrieve ignored state for 'tag' or 'type' or 'format'
 * @param {String | Array} ignore
 * @param {String} tag
 * @param {String} type
 * @param {String} format
 * @returns {Boolean}
 */
exports.isIgnored = function (ignore, tag, type, format) {
	// Clean svg+xml ==> svg
	var formatAlt = (format && format.indexOf('+'))
		? format.split('+')[0]
		: null;

	// Backwards compat for 3.x style format
	if (isPlainObject(ignore)) {
		var ig = [];
		for (var prop in ignore) {
			if (Array.isArray(ignore[prop])) {
				ig = ig.concat(ignore[prop]);
			} else {
				ig.push(ignore[prop]);
			}
		}
		ignore = ig;
	}

	if (!Array.isArray(ignore)) ignore = [ignore];

	return !!(~ignore.indexOf(tag) || ~ignore.indexOf(type) || ~ignore.indexOf(format) || ~ignore.indexOf(formatAlt));
};

/**
 * Escape 'str' for use in RegExp constructor
 * @param {String} str
 * @returns {String}
 */
exports.escape = function (str) {
	return str.replace(RE_ESCAPE, '\\$&');
};

/**
 * No op
 * @param {Error} [err]
 */
exports.noop = function (err) {
	if (err) throw err;
};<commit_msg>update inline tag regex<commit_after>'use strict';

var isPlainObject = require('lodash/lang/isPlainObject')
	, path = require('path')

	, ATTRIBUTE_BLACKLIST = ['href', 'rel', 'src']
	, RE_ESCAPE = /[-\/\\^$*+?.()|[\]{}]/g
		// Multiline, tags
	, RE_NOT_FILEPATH = /[\r\n<>]/gm;

/**
 * Determine if 'str' is likely a filepath
 * @param {String} str
 * @returns {Boolean}
 */
exports.isFilepath = function (str) {
	RE_NOT_FILEPATH.lastIndex = 0;
	if (str) return !RE_NOT_FILEPATH.test(str);
	return false;
};

/**
 * Retrieve tag regexp for 'attribute'
 * @param {String} attribute
 * @returns {RegExp}
 */
exports.getTagRegExp = function (attribute) {
	return new RegExp('<([a-zA-Z]+)\\b[^>]*?\\s' + attribute + '\\b[^>]*?>(?:<\\/\\1\\s?>)?', 'gm');
};

/**
 * Parse 'attributes'
 * @param {Object} attributes
 * @returns {Object}
 */
exports.parseAttributes = function (attributes) {
	for (var prop in attributes) {
		// Parse boolean values
		if (attributes[prop] === '') attributes[prop] = true;
	}

	return attributes;
};

/**
 * Parse props with 'prefix' from 'attributes'
 * @param {Object} attributes
 * @param {String} prefix
 * @returns {Object}
 */
exports.parseProps = function (attributes, prefix) {
	prefix += '-';

	var props = {};

	for (var prop in attributes) {
		// Strip 'inline-' and store
		if (prop.indexOf(prefix) == 0) {
			props[prop.slice(prefix.length)] = attributes[prop];
		}
	}

	return props;
};

/**
 * Retrieve resolved 'filepath'
 * @param {String} filepath
 * @param {String} htmlpath
 * @param {String} rootpath
 * @returns {String}
 */
exports.getSourcepath = function (filepath, htmlpath, rootpath) {
	if (filepath) {
		if (htmlpath && filepath.indexOf('./') == 0 || filepath.indexOf('../') == 0) {
			return path.resolve(path.dirname(htmlpath), filepath);
		} else {
			// Strip leading '/'
			if (filepath.indexOf('/') == 0) filepath = filepath.slice(1);
			return path.resolve(rootpath, filepath);
		}
	}

	return '';
};

/**
 * Retrieve type based on 'type'
 * @param {String} tag
 * @returns {String}
 */
exports.getTypeFromType = function (type) {
	if (type) {
		switch (type) {
			case 'application/javascript':
			case 'application/x-javascript':
			case 'application/ecmascript':
			case 'text/javascript':
			case 'text/ecmascript':
			case 'javascript':
			case 'js':
			case 'ecmascript':
				return 'js';
			case 'text/css':
			case 'css':
				return 'css';
			case 'image/png':
			case 'image/gif':
			case 'image/jpeg':
			case 'image/jpg':
			case 'image/svg+xml':
			case 'image/svg':
			case 'png':
			case 'gif':
			case 'jpeg':
			case 'jpg':
			case 'svg':
			case 'image':
				return 'image';
			case 'application/json':
			case 'text/json':
			case 'json':
				return 'json';
			default:
				return type;
		}
	}
};

/**
 * Retrieve type based on 'tag'
 * @param {String} tag
 * @returns {String}
 */
exports.getTypeFromTag = function (tag) {
	if (tag) {
		switch (tag) {
			case 'script':
				return 'js';
			case 'link':
				return 'css';
			case 'img':
				return 'image';
			default:
				return '';
		}
	}
};

/**
 * Retrieve format based on 'extension'
 * @param {String} extension
 * @returns {String}
 */
exports.getFormatFromExtension = function (extension) {
	if (extension) {
		switch (extension) {
			case 'js':
				return 'js';
			case 'json':
				return 'json';
			case 'css':
				return 'css';
			case 'gif':
				return 'gif';
			case 'png':
				return 'png';
			case 'jpeg':
			case 'jpg':
				return 'jpeg';
			case 'svg':
				return 'svg+xml';
			default:
				return extension;
		}
	}
};

/**
 * Retrieve leading whitespace for 'source' in 'html'
 * @param {String} source
 * @param {String} html
 * @returns {String}
 */
exports.getPadding = function (source, html) {
	var re = new RegExp('^([\\t ]+)' + exports.escape(source), 'gm')
		, match = re.exec(html);

	return match ? match[1] : '';
};

/**
 * Retrieve stringified attributes
 * @param {Object} attributes
 * @param {String} prefix
 * @param {Boolean} strict
 * @returns {String}
 */
exports.getAttributeString = function (attributes, prefix, strict) {
	var str = '';

	for (var prop in attributes) {
		// Ignore blacklisted and prefixed attributes
		var include = strict
			? prop.indexOf(prefix) != 0 && !~ATTRIBUTE_BLACKLIST.indexOf(prop)
			: prop.indexOf(prefix) != 0;

		if (include) {
			str += (attributes[prop] === true)
				? ' ' + prop
				: ' ' + prop + '="' + attributes[prop] + '"';
		}
	}

	return str;
};

/**
 * Retrieve ignored state for 'tag' or 'type' or 'format'
 * @param {String | Array} ignore
 * @param {String} tag
 * @param {String} type
 * @param {String} format
 * @returns {Boolean}
 */
exports.isIgnored = function (ignore, tag, type, format) {
	// Clean svg+xml ==> svg
	var formatAlt = (format && format.indexOf('+'))
		? format.split('+')[0]
		: null;

	// Backwards compat for 3.x style format
	if (isPlainObject(ignore)) {
		var ig = [];
		for (var prop in ignore) {
			if (Array.isArray(ignore[prop])) {
				ig = ig.concat(ignore[prop]);
			} else {
				ig.push(ignore[prop]);
			}
		}
		ignore = ig;
	}

	if (!Array.isArray(ignore)) ignore = [ignore];

	return !!(~ignore.indexOf(tag) || ~ignore.indexOf(type) || ~ignore.indexOf(format) || ~ignore.indexOf(formatAlt));
};

/**
 * Escape 'str' for use in RegExp constructor
 * @param {String} str
 * @returns {String}
 */
exports.escape = function (str) {
	return str.replace(RE_ESCAPE, '\\$&');
};

/**
 * No op
 * @param {Error} [err]
 */
exports.noop = function (err) {
	if (err) throw err;
};<|endoftext|>