code: function substituteFnWhereNeeded(actions) {
    actions = actions || [];
    return actions.map(function (action) {
      return Object.keys(action).reduce(function (accum, key) {
        if ((key === 'get' || key === 'head' || key === 'put' || key === 'post' || key === 'del' || key === 'patch') &&
            needsSubtitution(action[key])) {
          accum[key] = function (tokens) {
            return action[key].replace(/\#\{INDEX\}/g, tokens.INDEX);
          };
        } else if (key === 'json' && needsSubtitution(action[key])) {
          accum[key] = function (tokens) {
            return JSON.parse(JSON.stringify(action[key]).replace(/\#\{INDEX\}/g, tokens.INDEX));
          };
        } else if (key === 'body' && typeof action.body === 'string' && needsSubtitution(action[key])) {
          accum[key] = function (tokens) {
            return action[key].replace(/\#\{INDEX\}/g, tokens.INDEX);
          };
        } else {
          accum[key] = action[key];
        }
        return accum;
      }, {});
    });
  }
docs: create modified actions object which has substituteFns for any keys that
  are using substitution. These substituteFns have one argument `tokens` which
  will be bound to them in the queuing loop, so at runtime, the fn will be
  executed and returns the proper value.
  
  Keys which do not need substitution, will be returned untouched and thus
  will save the overhead of needing replacement and stringify/parse (json)
  
  If adding keys, be sure to update the SUBSTITUTED_KEYS constant.
  
  @returns actions object with replacements done as necessary