text: // Copyright (c) 2012, Mark Cavage. All rights reserved.
  // Copyright 2015 Joyent, Inc.
  
  var assert = require('assert');
  var Stream = require('stream').Stream;
  var util = require('util');
  
  ///--- Globals
  
  /* JSSTYLED */
  var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
  
  ///--- Internal
  
  function _capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
  
  function _toss(name, expected, oper, arg, actual) {
    throw new assert.AssertionError({
      message: util.format('%s (%s) is required', name, expected),
      actual: actual === undefined ? typeof arg : actual(arg),
      expected: expected,
      operator: oper || '===',
      stackStartFunction: _toss.caller
    });
  }
  
  function _getClass(arg) {
    return Object.prototype.toString.call(arg).slice(8, -1);
  }
  
  function noop() {
    // Why even bother with asserts?
  }
  
  ///--- Exports
  
  var types = {
    bool: {
      check: function(arg) {
        return typeof arg === 'boolean';
      }
    },
    func: {
      check: function(arg) {
        return typeof arg === 'function';
      }
    },
    string: {
      check: function(arg) {
        return typeof arg === 'string';
      }
    },
    object: {
      check: function(arg) {
        return typeof arg === 'object' && arg !== null;
      }
    },
    number: {
      check: function(arg) {
        return typeof arg === 'number' && !isNaN(arg);
      }
    },
    finite: {
      check: function(arg) {
        return typeof arg === 'number' && !isNaN(arg) && isFinite(arg);
      }
    },
    buffer: {
      check: function(arg) {
        return Buffer.isBuffer(arg);
      },
      operator: 'Buffer.isBuffer'
    },
    array: {
      check: function(arg) {
        return Array.isArray(arg);
      },
      operator: 'Array.isArray'
    },
    stream: {
      check: function(arg) {
        return arg instanceof Stream;
      },
      operator: 'instanceof',
      actual: _getClass
    },
    date: {
      check: function(arg) {
        return arg instanceof Date;
      },
      operator: 'instanceof',
      actual: _getClass
    },
    regexp: {
      check: function(arg) {
        return arg instanceof RegExp;
      },
      operator: 'instanceof',
      actual: _getClass
    },
    uuid: {
      check: function(arg) {
        return typeof arg === 'string' && UUID_REGEXP.test(arg);
      },
      operator: 'isUUID'
    }
  };
  
  function _setExports(ndebug) {
    var keys = Object.keys(types);
    var out;
  
    /* re-export standard assert */
    if (process.env.NODE_NDEBUG) {
      out = noop;
    } else {
      out = function(arg, msg) {
        if (!arg) {
          _toss(msg, 'true', arg);
        }
      };
    }
  
    /* standard checks */
    keys.forEach(function(k) {
      if (ndebug) {
        out[k] = noop;
        return;
      }
      var type = types[k];
      out[k] = function(arg, msg) {
        if (!type.check(arg)) {
          _toss(msg, k, type.operator, arg, type.actual);
        }
      };
    });
  
    /* optional checks */
    keys.forEach(function(k) {
      var name = 'optional' + _capitalize(k);
      if (ndebug) {
        out[name] = noop;
        return;
      }
      var type = types[k];
      out[name] = function(arg, msg) {
        if (arg === undefined || arg === null) {
          return;
        }
        if (!type.check(arg)) {
          _toss(msg, k, type.operator, arg, type.actual);
        }
      };
    });
  
    /* arrayOf checks */
    keys.forEach(function(k) {
      var name = 'arrayOf' + _capitalize(k);
      if (ndebug) {
        out[name] = noop;
        return;
      }
      var type = types[k];
      var expected = '[' + k + ']';
      out[name] = function(arg, msg) {
        if (!Array.isArray(arg)) {
          _toss(msg, expected, type.operator, arg, type.actual);
        }
        var i;
        for (i = 0; i < arg.length; i++) {
          if (!type.check(arg[i])) {
            _toss(msg, expected, type.operator, arg, type.actual);
          }
        }
      };
    });
  
    /* optionalArrayOf checks */
    keys.forEach(function(k) {
      var name = 'optionalArrayOf' + _capitalize(k);
      if (ndebug) {
        out[name] = noop;
        return;
      }
      var type = types[k];
      var expected = '[' + k + ']';
      out[name] = function(arg, msg) {
        if (arg === undefined || arg === null) {
          return;
        }
        if (!Array.isArray(arg)) {
          _toss(msg, expected, type.operator, arg, type.actual);
        }
        var i;
        for (i = 0; i < arg.length; i++) {
          if (!type.check(arg[i])) {
            _toss(msg, expected, type.operator, arg, type.actual);
          }
        }
      };
    });
  
    /* re-export built-in assertions */
    Object.keys(assert).forEach(function(k) {
      if (k === 'AssertionError') {
        out[k] = assert[k];
        return;
      }
      if (ndebug) {
        out[k] = noop;
        return;
      }
      out[k] = assert[k];
    });
  
    /* export ourselves (for unit tests _only_) */
    out._setExports = _setExports;
  
    return out;
  }
  
  module.exports = _setExports(process.env.NODE_NDEBUG);
  