text: 'use strict'
  
  const multihash = require('multihashes')
  const crypto = require('./crypto')
  
  module.exports = Multihashing
  
  /**
   * Hash the given `buf` using the algorithm specified
   * by `func`.
   *
   * @param {Buffer} buf - The value to hash.
   * @param {number|string} func - The algorithm to use.
   * @param {number} [length] - Optionally trim the result to this length.
   * @param {function(Error, Buffer)} callback
   * @returns {undefined}
   */
  function Multihashing (buf, func, length, callback) {
    if (typeof length === 'function') {
      callback = length
      length = undefined
    }
  
    if (!callback) {
      throw new Error('Missing callback')
    }
  
    Multihashing.digest(buf, func, length, (err, digest) => {
      if (err) {
        return callback(err)
      }
  
      callback(null, multihash.encode(digest, func, length))
    })
  }
  
  /**
   * The `buffer` module for easy use in the browser.
   *
   * @type {Buffer}
   */
  Multihashing.Buffer = Buffer // for browser things
  
  /**
   * Expose multihash itself, to avoid silly double requires.
   */
  Multihashing.multihash = multihash
  
  /**
   * @param {Buffer} buf - The value to hash.
   * @param {number|string} func - The algorithm to use.
   * @param {number} [length] - Optionally trim the result to this length.
   * @param {function(Error, Buffer)} callback
   * @returns {undefined}
   */
  Multihashing.digest = function (buf, func, length, callback) {
    if (typeof length === 'function') {
      callback = length
      length = undefined
    }
  
    if (!callback) {
      throw new Error('Missing callback')
    }
  
    let cb = callback
    if (length) {
      cb = (err, digest) => {
        if (err) {
          return callback(err)
        }
  
        callback(null, digest.slice(0, length))
      }
    }
  
    let hash
    try {
      hash = Multihashing.createHash(func)
    } catch (err) {
      return cb(err)
    }
  
    hash(buf, cb)
  }
  
  /**
   * @param {string|number} func
   *
   * @returns {function} - The to `func` corresponding hash function.
   */
  Multihashing.createHash = function (func) {
    func = multihash.coerceCode(func)
    if (!Multihashing.functions[func]) {
      throw new Error('multihash function ' + func + ' not yet supported')
    }
  
    return Multihashing.functions[func]
  }
  
  /**
   * Mapping of multihash codes to their hashing functions.
   * @type {Object}
   */
  Multihashing.functions = {
    // sha1
    0x11: crypto.sha1,
    // sha2-256
    0x12: crypto.sha2256,
    // sha2-512
    0x13: crypto.sha2512,
    // sha3-512
    0x14: crypto.sha3512,
    // sha3-384
    0x15: crypto.sha3384,
    // sha3-256
    0x16: crypto.sha3256,
    // sha3-224
    0x17: crypto.sha3224,
    // shake-128
    0x18: crypto.shake128,
    // shake-256
    0x19: crypto.shake256,
    // keccak-224
    0x1A: crypto.keccak224,
    // keccak-256
    0x1B: crypto.keccak256,
    // keccak-384
    0x1C: crypto.keccak384,
    // keccak-512
    0x1D: crypto.keccak512,
    // murmur3-128
    0x22: crypto.murmur3128,
    // murmur3-32
    0x23: crypto.murmur332,
    // dbl-sha2-256
    0x56: crypto.dblSha2256
  }
  
  // add blake functions
  crypto.addBlake(Multihashing.functions)
  