text: (function (exports, TEST) {
  'use strict';
  
  var crypto;
  var sha1Hmac = exports.sha1Hmac || function (key, bytes) {
    if (!crypto) { crypto = require('crypto'); }
  
    var hmac = crypto.createHmac('sha1', new Buffer(key));
    // Update the HMAC with the byte array
    return hmac.update(new Buffer(bytes)).digest('hex');
  };
  
  /**
   * convert an integer to a byte array
   * @param {Integer} num
   * @return {Array} bytes
   */
  function intToBytes(num) {
    var bytes = [];
  
    for(var i=7 ; i>=0 ; --i) {
      bytes[i] = num & (255);
      num = num >> 8;
    }
  
    return bytes;
  }
  
  /**
   * convert a hex value to a byte array
   * @param {String} hex string of hex to convert to a byte array
   * @return {Array} bytes
   */
  function hexToBytes(hex) {
    var bytes = [];
    for(var c = 0, C = hex.length; c < C; c += 2) {
      bytes.push(parseInt(hex.substr(c, 2), 16));
    }
    return bytes;
  }
  
  var hotp = {};
  
  /**
   * Generate a counter based One Time Password
   *
   * @return {String} the one time password
   *
   * Arguments:
   *
   *  args
   *     key - Key for the one time password.  This should be unique and secret for
   *         every user as this is the seed that is used to calculate the HMAC
   *
   *     counter - Counter value.  This should be stored by the application, must
   *         be user specific, and be incremented for each request.
   *
   */
  hotp.gen = function(key, opt) {
    key = key || '';
    opt = opt || {};
    var counter = opt.counter || 0;
  
    // Create the byte array
    return sha1Hmac(key, intToBytes(counter)).then(function (digest) {
      // Get byte array
      var h = hexToBytes(digest);
  
      // Truncate
      var offset = h[19] & 0xf;
      var v = (h[offset] & 0x7f) << 24 |
        (h[offset + 1] & 0xff) << 16 |
        (h[offset + 2] & 0xff) << 8  |
        (h[offset + 3] & 0xff);
  
      v = (v % 1000000) + '';
  
      return new Array(7-v.length).join('0') + v;
    });
  };
  
  /**
   * Check a One Time Password based on a counter.
   *
   * @return {Object} null if failure, { delta: # } on success
   * delta is the time step difference between the client and the server
   *
   * Arguments:
   *
   *  args
   *     key - Key for the one time password.  This should be unique and secret for
   *         every user as it is the seed used to calculate the HMAC
   *
   *     token - Passcode to validate.
   *
   *     window - The allowable margin for the counter.  The function will check
   *         'W' codes in the future against the provided passcode.  Note,
   *         it is the calling applications responsibility to keep track of
   *         'W' and increment it for each password check, and also to adjust
   *         it accordingly in the case where the client and server become
   *         out of sync (second argument returns non zero).
   *         E.g. if W = 100, and C = 5, this function will check the passcode
   *         against all One Time Passcodes between 5 and 105.
   *
   *         Default - 50
   *
   *     counter - Counter value.  This should be stored by the application, must
   *         be user specific, and be incremented for each request.
   *
   */
  hotp.verify = function(token, key, opt) {
    opt = opt || {};
    var window = opt.window || 50;
    var counter = opt.counter || 0;
    var i = counter - window;
    var len = counter + window;
  
    // Now loop through from C to C + W to determine if there is
    // a correct code
    function check(t) {
      opt.counter = i + 1;
  
      if (!t) {
        return null;
      }
  
      if (i > len) {
        return null;
      }
  
      if(t === token) {
        // We have found a matching code, trigger callback
        // and pass offset
        return i;
      }
  
      // TODO count 0, -1, 1, -2, 2, ... instead of -2, -1, 0, 1, ...
      i += 1;
  
      return hotp.gen(key, opt).then(check);
    }
  
    opt.counter = i;
    return hotp.gen(key, opt).then(check).then(function (i) {
      if('number' === typeof i) {
        return { delta: i - counter };
      }
  
      // If we get to here then no codes have matched, return null
      return null;
    });
  };
  
  var totp = {};
  
  /**
   * Generate a time based One Time Password
   *
   * @return {String} the one time password
   *
   * Arguments:
   *
   *  args
   *     key - Key for the one time password.  This should be unique and secret for
   *         every user as it is the seed used to calculate the HMAC
   *
   *     time - The time step of the counter.  This must be the same for
   *         every request and is used to calculat C.
   *
   *         Default - 30
   *
   */
  totp.gen = function(key, opt) {
    opt = opt || {};
    var time = opt.time || 30;
    var _t = Date.now();
  
    // Time has been overwritten.
    if(opt._t) {
      if(!TEST) {
        console.warn('Overwriting time in non-test environment!');
      }
      _t = opt._t;
    }
  
    // Determine the value of the counter, C
    // This is the number of time steps in seconds since T0
    opt.counter = Math.floor((_t / 1000) / time);
  
    return hotp.gen(key, opt);
  };
  
  /**
   * Check a One Time Password based on a timer.
   *
   * @return {Object} null if failure, { delta: # } on success
   * delta is the time step difference between the client and the server
   *
   * Arguments:
   *
   *  args
   *     key - Key for the one time password.  This should be unique and secret for
   *         every user as it is the seed used to calculate the HMAC
   *
   *     token - Passcode to validate.
   *
   *     window - The allowable margin for the counter.  The function will check
   *         'W' codes either side of the provided counter.  Note,
   *         it is the calling applications responsibility to keep track of
   *         'W' and increment it for each password check, and also to adjust
   *         it accordingly in the case where the client and server become
   *         out of sync (second argument returns non zero).
   *         E.g. if W = 5, and C = 1000, this function will check the passcode
   *         against all One Time Passcodes between 995 and 1005.
   *
   *         Default - 6
   *
   *     time - The time step of the counter.  This must be the same for
   *         every request and is used to calculate C.
   *
   *         Default - 30
   *
   */
  totp.verify = function(token, key, opt) {
    opt = opt || {};
    var time = opt.time || 30;
    var _t = Date.now();
  
    // Time has been overwritten.
    if(opt._t) {
      if(!TEST) {
        console.warn('Overwriting time in non-test environment!');
      }
      _t = opt._t;
    }
  
    // Determine the value of the counter, C
    // This is the number of time steps in seconds since T0
    opt.counter = Math.floor((_t / 1000) / time);
  
    return hotp.verify(token, key, opt);
  };
  
  exports.hotp = hotp;
  exports.totp = totp;
  }(
    'undefined' !== typeof window ? window : module.exports
  , 'undefined' !== typeof process ? process.env.NODE_ENV : false
  ));
  