docs: function (options, callback) {
      if (!options) {
        throw new Error('You must provide an options object.');
      }
  
      if (!options.packName) {
        throw new Error('You must provide a pack name the card belongs to.');
      }
  
      if (!options.cardName) {
        throw new Error('You must provide a card name of the card to render.');
      }
  
      options.directory = options.directory || process.cwd();
      options.inputValues = options.inputValues || {};
  
      var packPath = Path.join(options.directory, 'hashdo-' + options.packName.replace('hashdo-', '')),
        cardFile = Path.join(packPath, options.cardName) + '.js';
  
      // check for card pack
      FS.stat(packPath, function (err) {
        if (!err) {
  
          // check for card
          FS.stat(cardFile, function (err) {
            if (!err) {
  
              // Remove card from cache to ease development by reloading from disk each time.
              if (process.env.NODE_ENV !== 'production') {
                delete require.cache[require.resolve(Path.join(packPath, options.cardName))];
              }
  
              var Card = require(Path.join(packPath, options.cardName)),
                DB = require('../index').db;
  
              Async.waterfall([
  
                  // get required params
                  function (cb) {
                    // card key
                    var url = options.url.replace(/light=true/i, ''),
                      params = {
                        legacyCardKey: Utils.getLegacyCardKey(url, process.env.CARD_SECRET),
                        cardKey: Utils.getCardKey(url, process.env.CARD_SECRET)
                      };
  
                    // extract input values
                    _.each(_.keys(options.inputValues), function (key) {
                      params[key] = options.inputValues[key];
                    });
  
                    if (options.inputValues.token) {
  
                      // retrieve previously saved parameters. Add or replace params
                      DB.unlock(options.packName, options.cardName, options.inputValues.token, process.env.LOCK_KEY, function (err, payload) {
                        if (err) {
                          // Ignore error and just return the params.
                          cb(null, params);
                        }
                        else {
                          if (payload && _.isObject(payload)) {
                            _.each(_.keys(Card.inputs), function (key) {
                              if (payload[key]) {
                                params[key] = Base64.decode(payload[key]);
                              }
                            });
                          }
  
                          cb(null, params);
                        }
                      });
                    }
                    else {
                      cb(null, params);
                    }
                  },
  
                  // check for input validation errors
                  function (params, cb) {
                    // validate input requirements vs what came back in params
                    var errorMessage = null;
  
                    _.forEach(Card.inputs, function (input, key) {
                      if (input.required && !params[key]) {
                        if (!errorMessage) {
                          errorMessage = '';
                        }
                        else {
                          errorMessage += ' | ';
                        }
  
                        errorMessage += 'No value provided for required input: ' + key;
                      }
                    });
  
                    cb(errorMessage, params);
                  }
                ],
  
                // done - respond with params
                function (err, params) {
                  if (!err) {
                    callback && callback(null, params);
                  }
                  else {
                    callback && callback(err.message || err);
                  }
                }
              );
            }
            else {
              callback && callback('Card (' + options.cardName + ') not found within ' + options.packName);
            }
          });
        }
        else {
          // callback && callback('Card not found within ' + cardDirectory);
          callback && callback('Card pack not found (' + options.packName + ').');
        }
      });
    }