var isArrayLike = require('toolz/src/lang/isArrayLike')

function kindOf (value) {
  return typeof value === 'object'
    ? Object.prototype.toString.call(value)
      .replace(/^\[object |\]$/g, '')
      .toLowerCase()
    : typeof value
}

function kindOfBase (value) {
  // Base implementation which all other kindOf
  // functions were morphed from and compared to.
  // Does not handle arguments
  if (value === null) return 'null'
  if (value === undefined) return 'undefined'

  if (Array.isArray(value)) return 'array'

  var type = value.constructor.name

  if (type === 'String') return 'string'
  if (type === 'Boolean') return 'boolean'
  if (type === 'Number') return 'number'
  if (type === 'Symbol') return 'symbol'
  if (type === 'Function') return 'function'
  if (type === 'Object') return 'object'
  if (type === 'Date') return 'date'
  if (type === 'RegExp') return 'regexp'

  return type.toLowerCase()
}

function kindOfType (value) {
  // Return the constructor name if not a primative, array or function
  // A more performant `kindOf` with cavets. Must test ES6 after upgrade.
  // Does not handle arguments.
  if (value === null) return 'null'
  if (value === undefined) return 'undefined'

  if (Array.isArray(value)) return 'array'

  if (typeof value === 'string') return 'string'
  if (typeof value === 'boolean') return 'boolean'
  if (typeof value === 'number') return 'number'
  if (typeof value === 'symbol') return 'symbol'
  if (typeof value === 'function') return 'function'

  // this will pick out PlainObjects, regexps, and dates
  // quicker than a toString.call() but marginally slower
  // than the base implementation. Fails on arguments,
  // not really though --> arguments [object]
  var type = value.constructor.name

  if (type === 'Object') return 'object'
  if (type === 'RegExp') return 'regexp'
  if (type === 'Date') return 'date'

  return type.toLowerCase()
}

function kindOfObjs (value) {
  // a speedy version to obtain common object "types"
  // Does not handle arguments.
  if (typeof value === 'function') return 'function'
  if (Array.isArray(value)) return 'array'
  if (typeof value === 'string') return 'string'

  var type = value.constructor.name

  if (type === 'Object') return 'object'
  if (type === 'RegExp') return 'regexp'
  if (type === 'Date') return 'date'

  return type.toLowerCase()
}

function kindOfSafe (value) {
  if (value === null) return 'null'
  if (value === undefined) return 'undefined'

  if (Array.isArray(value)) return 'array'

  if (typeof value === 'string') return 'string'
  if (typeof value === 'boolean') return 'boolean'
  if (typeof value === 'number') return 'number'
  if (typeof value === 'symbol') return 'symbol'
  if (typeof value === 'function') return 'function'

  // Object.create(null) throws an error. Code below
  // prevents this from happening. Handles arguments.
  try {
    var type = value.constructor.name

    if (type === 'Object') {
      return isArrayLike(value)
        ? 'arguments'
        : 'object'
    }

    if (type === 'RegExp') return 'regexp'
    if (type === 'Date') return 'date'

    return type.toLowerCase()
  } catch (err) {
    return Object.prototype.toString.call(value)
      .replace(/^\[object |\]$/g, '')
      .toLowerCase()
  }
}

module.exports = kindOf
module.exports.base = kindOfBase
module.exports.type = kindOfType
module.exports.objs = kindOfObjs
module.exports.safe = kindOfSafe

@@ -803,32 +803,73 @@
 return 'object'%0A
+  if (type === 'RegExp') return 'regexp'%0A
   if (type === '
@@ -897,38 +897,38 @@
   if (type === '
-RegExp
+Buffer
 ') return 'regex
@@ -922,22 +922,22 @@
 return '
-regexp
+buffer
 '%0A%0A  ret
@@ -1911,32 +1911,73 @@
 ') return 'date'
+%0A  if (type === 'Buffer') return 'buffer'
 %0A%0A  return type.
@@ -2406,24 +2406,65 @@
 eturn 'date'
+%0A  if (type === 'Buffer') return 'buffer'
 %0A%0A  return t
@@ -3199,16 +3199,16 @@
 regexp'%0A
-
     if (
@@ -3237,16 +3237,59 @@
 n 'date'
+%0A    if (type === 'Buffer') return 'buffer'
 %0A%0A    re

update lang/kindOf -- add buffer check