docs: function(attr, options) {
                      // check if we should only look within current scope
                      var stopLookup;
                      if (attr.substr(0, 2) === './') {
                          // set flag to halt lookup from walking up scope
                          stopLookup = true;
                          // stop lookup from checking parent scopes
                          attr = attr.substr(2);
                      }
                      // check if we should be running this on a parent.
                      else if (attr.substr(0, 3) === "../") {
                          return this._parent.read(attr.substr(3), options);
                      } else if (attr === "..") {
                          return {
                              value: this._parent._context
                          };
                      } else if (attr === "." || attr === "this") {
                          return {
                              value: this._context
                          };
                      }
  
                      // Array of names from splitting attr string into names.  ```"a.b\.c.d\\.e" //-> ['a', 'b', 'c', 'd.e']```
                      var names = attr.indexOf('\\.') === -1 ?
                      // Reference doesn't contain escaped periods
                      attr.split('.')
                      // Reference contains escaped periods ```(`a.b\.c.foo` == `a["b.c"].foo)```
                      : getNames(attr),
                          // The current context (a scope is just data and a parent scope).
                          context,
                          // The current scope.
                          scope = this,
                          // While we are looking for a value, we track the most likely place this value will be found.
                          // This is so if there is no me.name.first, we setup a listener on me.name.
                          // The most likely candidate is the one with the most "read matches" "lowest" in the
                          // context chain.
                          // By "read matches", we mean the most number of values along the key.
                          // By "lowest" in the context chain, we mean the closest to the current context.
                          // We track the starting position of the likely place with `defaultObserve`.
                          defaultObserve,
                          // Tracks how to read from the defaultObserve.
                          defaultReads = [],
                          // Tracks the highest found number of "read matches".
                          defaultPropertyDepth = -1,
                          // `scope.read` is designed to be called within a compute, but
                          // for performance reasons only listens to observables within one context.
                          // This is to say, if you have me.name in the current context, but me.name.first and
                          // we are looking for me.name.first, we don't setup bindings on me.name and me.name.first.
                          // To make this happen, we clear readings if they do not find a value.  But,
                          // if that path turns out to be the default read, we need to restore them.  This
                          // variable remembers those reads so they can be restored.
                          defaultComputeReadings,
                          // Tracks the default's scope.
                          defaultScope,
                          // Tracks the first found observe.
                          currentObserve,
                          // Tracks the reads to get the value for a scope.
                          currentReads;
  
                      // Goes through each scope context provided until it finds the key (attr).  Once the key is found
                      // then it's value is returned along with an observe, the current scope and reads.
                      // While going through each scope context searching for the key, each observable found is returned and
                      // saved so that either the observable the key is found in can be returned, or in the case the key is not
                      // found in an observable the closest observable can be returned.
  
                      while (scope) {
                          context = scope._context;
                          if (context !== null) {
                              var data = can.compute.read(context, names, can.simpleExtend({
  
                                          foundObservable: function(observe, nameIndex) {
                                              currentObserve = observe;
                                              currentReads = names.slice(nameIndex);
                                          },
                                          // Called when we were unable to find a value.
                                          earlyExit: function(parentValue, nameIndex) {
  
                                              if (nameIndex > defaultPropertyDepth) {
                                                  defaultObserve = currentObserve;
                                                  defaultReads = currentReads;
                                                  defaultPropertyDepth = nameIndex;
                                                  defaultScope = scope;
  
                                                  defaultComputeReadings = can.__clearReading();
                                              }
                                          },
                                          // Execute anonymous functions found along the way
                                          executeAnonymousFunctions: true
                                      }, options));
                              // **Key was found**, return value and location data
                              if (data.value !== undefined) {
                                  return {
                                      scope: scope,
                                      rootObserve: currentObserve,
                                      value: data.value,
                                      reads: currentReads
                                  };
                              }
                          }
                          // Prevent prior readings and then move up to the next scope.
                          can.__clearReading();
                          if (!stopLookup) {
                              // Move up to the next scope.
                              scope = scope._parent;
                          } else {
                              scope = null;
                          }
                      }
  
                      // **Key was not found**, return undefined for the value.  Unless an observable was
                      // found in the process of searching for the key, then return the most likely observable along with it's
                      // scope and reads.
  
                      if (defaultObserve) {
                          can.__setReading(defaultComputeReadings);
                          return {
                              scope: defaultScope,
                              rootObserve: defaultObserve,
                              reads: defaultReads,
                              value: undefined
                          };
                      } else {
                          return {
                              names: names,
                              value: undefined
                          };
                      }
                  }