docs: function forProps() {
      var forShadowed,
          skipSeen,
          forArgs = true,
          shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
  
      (function(enumFlag, key) {
        // must use a non-native constructor to catch the Safari 2 issue
        function Klass() { this.valueOf = 0; };
        Klass.prototype.valueOf = 0;
        // check various for-in bugs
        for (key in new Klass) {
          enumFlag += key == 'valueOf' ? 1 : 0;
        }
        // check if `arguments` objects have non-enumerable indexes
        for (key in arguments) {
          key == '0' && (forArgs = false);
        }
        // Safari 2 iterates over shadowed properties twice
        // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/
        skipSeen = enumFlag == 2;
        // IE < 9 incorrectly makes an object's properties non-enumerable if they have
        // the same name as other non-enumerable properties in its prototype chain.
        forShadowed = !enumFlag;
      }(0));
  
      // lazy define
      forProps = function(object, callback, options) {
        options || (options = {});
  
        var result = object;
        object = Object(object);
  
        var ctor,
            key,
            keys,
            skipCtor,
            done = !result,
            which = options.which,
            allFlag = which == 'all',
            index = -1,
            iteratee = object,
            length = object.length,
            ownFlag = allFlag || which == 'own',
            seen = {},
            skipProto = isClassOf(object, 'Function'),
            thisArg = options.bind;
  
        if (thisArg !== undefined) {
          callback = bind(callback, thisArg);
        }
        // iterate all properties
        if (allFlag && support.getAllKeys) {
          for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) {
            key = keys[index];
            if (callback(object[key], key, object) === false) {
              break;
            }
          }
        }
        // else iterate only enumerable properties
        else {
          for (key in object) {
            // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
            // (if the prototype or a property on the prototype has been set)
            // incorrectly set a function's `prototype` property [[Enumerable]] value
            // to `true`. Because of this we standardize on skipping the `prototype`
            // property of functions regardless of their [[Enumerable]] value.
            if ((done =
                !(skipProto && key == 'prototype') &&
                !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) &&
                (!ownFlag || ownFlag && hasKey(object, key)) &&
                callback(object[key], key, object) === false)) {
              break;
            }
          }
          // in IE < 9 strings don't support accessing characters by index
          if (!done && (forArgs && isArguments(object) ||
              ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') &&
                (iteratee = noCharByIndex ? object.split('') : object)))) {
            while (++index < length) {
              if ((done =
                  callback(iteratee[index], String(index), object) === false)) {
                break;
              }
            }
          }
          if (!done && forShadowed) {
            // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing
            // property and the `constructor` property of a prototype defaults to
            // non-enumerable, we manually skip the `constructor` property when we
            // think we are iterating over a `prototype` object.
            ctor = object.constructor;
            skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor;
            for (index = 0; index < 7; index++) {
              key = shadowed[index];
              if (!(skipCtor && key == 'constructor') &&
                  hasKey(object, key) &&
                  callback(object[key], key, object) === false) {
                break;
              }
            }
          }
        }
        return result;
      };
      return forProps.apply(null, arguments);
    }