function crawl (obj, path, pathFromRoot, parents, $refs, options) {
var dereferenced;
var result = {
  value: obj,
  circular: false
};

if (obj && typeof obj === 'object') {
  parents.push(obj);

  if ($Ref.isAllowed$Ref(obj, options)) {
    dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, $refs, options);
    result.circular = dereferenced.circular;
    result.value = dereferenced.value;
  }
  else {
    Object.keys(obj).forEach(function (key) {
      var keyPath = Pointer.join(path, key);
      var keyPathFromRoot = Pointer.join(pathFromRoot, key);
      var value = obj[key];
      var circular = false;

      if ($Ref.isAllowed$Ref(value, options)) {
        dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, $refs, options);
        circular = dereferenced.circular;
        obj[key] = dereferenced.value;
      }
      else {
        if (parents.indexOf(value) === -1) {
          dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, $refs, options);
          circular = dereferenced.circular;
          obj[key] = dereferenced.value;
        }
        else {
          circular = foundCircularReference(keyPath, $refs, options);
        }
      }

      // Set the "isCircular" flag if this or any other property is circular
      result.circular = result.circular || circular;
    });
  }

  parents.pop();
}

return result;
}
Recursively crawls the given value, and dereferences any JSON references.

@param {*} obj - The value to crawl. If it's not an object or array, it will be ignored.
@param {string} path - The full path of `obj`, possibly with a JSON Pointer in the hash
@param {string} pathFromRoot - The path of `obj` from the schema root
@param {object[]} parents - An array of the parent objects that have already been dereferenced
@param {$Refs} $refs
@param {$RefParserOptions} options
@returns {{value: object, circular: boolean}}