/**

* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*
* Expose `debug()` as the module.
*/

exports = module.exports = createDebug.debug = createDebug = createDebug; exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; exports.humanize = require('ms');

/**

* The currently active debug mode names, and names to skip.
*/

exports.names = []; exports.skips = [];

/**

* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
*/

exports.formatters = {};

/**

* Previous log timestamp.
*/

var prevTime;

/**

* Select a color.
* @param {String} namespace
* @return {Number}
* @api private
*/

function selectColor(namespace) {

var hash = 0, i;

for (i in namespace) {
  hash  = ((hash << 5) - hash) + namespace.charCodeAt(i);
  hash |= 0; // Convert to 32bit integer
}

return exports.colors[Math.abs(hash) % exports.colors.length];

}

/**

* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/

function createDebug(namespace) {

function debug() {
  // disabled?
  if (!debug.enabled) return;

  var self = debug;

  // set `diff` timestamp
  var curr = +new Date();
  var ms = curr - (prevTime || curr);
  self.diff = ms;
  self.prev = prevTime;
  self.curr = curr;
  prevTime = curr;

  // turn the `arguments` into a proper Array
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; i++) {
    args[i] = arguments[i];
  }

  args[0] = exports.coerce(args[0]);

  if ('string' !== typeof args[0]) {
    // anything else let's inspect with %O
    args.unshift('%O');
  }

  // apply any `formatters` transformations
  var index = 0;
  args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
    // if we encounter an escaped % then don't increase the array index
    if (match === '%%') return match;
    index++;
    var formatter = exports.formatters[format];
    if ('function' === typeof formatter) {
      var val = args[index];
      match = formatter.call(self, val);

      // now we need to remove `args[index]` since it's inlined in the `format`
      args.splice(index, 1);
      index--;
    }
    return match;
  });

  // apply env-specific formatting (colors, etc.)
  exports.formatArgs.call(self, args);

  var logFn = debug.log || exports.log || console.log.bind(console);
  logFn.apply(self, args);
}

debug.namespace = namespace;
debug.enabled = exports.enabled(namespace);
debug.useColors = exports.useColors();
debug.color = selectColor(namespace);

// env-specific initialization logic for debug instances
if ('function' === typeof exports.init) {
  exports.init(debug);
}

return debug;

}

/**

* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/

function enable(namespaces) {

exports.save(namespaces);

exports.names = [];
exports.skips = [];

var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
var len = split.length;

for (var i = 0; i < len; i++) {
  if (!split[i]) continue; // ignore empty strings
  namespaces = split[i].replace(/\*/g, '.*?');
  if (namespaces[0] === '-') {
    exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
  } else {
    exports.names.push(new RegExp('^' + namespaces + '$'));
  }
}

}

/**

* Disable debug output.
*
* @api public
*/

function disable() {

exports.enable('');

}

/**

* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/

function enabled(name) {

var i, len;
for (i = 0, len = exports.skips.length; i < len; i++) {
  if (exports.skips[i].test(name)) {
    return false;
  }
}
for (i = 0, len = exports.names.length; i < len; i++) {
  if (exports.names[i].test(name)) {
    return true;
  }
}
return false;

}

/**

* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/

function coerce(val) {

if (val instanceof Error) return val.stack || val.message;
return val;

}