code: function runAfter (args, methodMeta, ret) {
      // return original promise if there are no after extensions
      if (!defined(methodMeta.after)) {
          return ret
      }
      // after original promise resolves then run after methods
      return ret.then(res => {
          // build arguments for after methods
          args = {
              args: defined(args.args) ? args.args : args,
              res: res,
              origRes: defined(args.origRes) ? args.origRes : args.res,
              session: args.session,
          }
          // wait for all extension methods to complete
          return Promise.all(
              // run all after methods in order making sure they return promise
              _.map(methodMeta.after, method => {
                  return (method)(args, methodMeta.signature, 'after')
              })
          )
          // merge returned data into original
          .then(function (results) {
              // either merge or replace result
              _.each(results, result => {
                  // both original res and after result are objects
                  if (typeof res === 'object' && res !== null && typeof result === 'object' && result !== null) {
                      // merge after into original
                      _.merge(res, result)
                  }
                  // one is not an object
                  else if (result !== undefined) {
                      // replace original with after
                      res = result
                  }
              })
              // return final result
              return res
          })
      })
  }
docs: @function runAfter
  
  run all extensions bound after method. if any extensions reject then the
  parent method will reject.
  
  any data returned by extensions will be merged into the parent return data.
  
  @param {object} args
  @param {object} methodMeta
  @param {object} ret
  
  @returns {Promise}