docs: function(keyReads, options, howToRead) {
  		// The current scope and context we are trying to find "keyReads" within.
  		var currentScope = this,
  			currentContext,
  
  			// If no value can be found, this is a list of of every observed
  			// object and property name to observe.
  			undefinedObserves = [],
  
  			// Tracks the first found observe.
  			currentObserve,
  			// Tracks the reads to get the value from `currentObserve`.
  			currentReads,
  
  			// Tracks the most likely observable to use as a setter.
  			setObserveDepth = -1,
  			currentSetReads,
  			currentSetObserve,
  
  			readOptions = assign({
  				/* Store found observable, incase we want to set it as the rootObserve. */
  				foundObservable: function(observe, nameIndex) {
  					currentObserve = observe;
  					currentReads = keyReads.slice(nameIndex);
  				},
  				earlyExit: function(parentValue, nameIndex) {
  					var isVariableScope = currentScope._meta.variable === true,
  						updateSetObservable = false;
  					if(isVariableScope === true && nameIndex === 0) {
  						// we MUST have pre-defined the key in a variable scope
  						updateSetObservable = canReflect.hasKey( parentValue, keyReads[nameIndex].key);
  					} else {
  						updateSetObservable =
  							// Has more matches
  							nameIndex > setObserveDepth ||
  							// The same number of matches but it has the key
  							nameIndex === setObserveDepth && (typeof parentValue === "object" && canReflect.hasOwnKey( parentValue, keyReads[nameIndex].key));
  					}
  					if ( updateSetObservable ) {
  						currentSetObserve = currentObserve;
  						currentSetReads = currentReads;
  						setObserveDepth = nameIndex;
  					}
  				}
  			}, options);
  
  
  
  		var isRecording = ObservationRecorder.isRecording(),
  			readAContext = false;
  
  		// 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 (currentScope) {
  
  			if(howToRead.shouldSkip(currentScope) === true) {
  				currentScope = currentScope._parent;
  				continue;
  			}
  			if(howToRead.shouldExit(currentScope) === true) {
  				break;
  			}
  			readAContext = true;
  
  			currentContext = currentScope._context;
  
  
  			// Prevent computes from temporarily observing the reading of observables.
  			var getObserves = ObservationRecorder.trap();
  
  			var data = howToRead.read(currentContext, keyReads, readOptions);
  
  			// Retrieve the observes that were read.
  			var observes = getObserves();
  			// If a **value was was found**, return value and location data.
  			if (data.value !== undefined || data.parentHasKey) {
  
  				if(!observes.length && isRecording) {
  					// if we didn't actually observe anything
  					// the reads and currentObserve don't mean anything
  					// we just point to the current object so setting is fast
  					currentObserve = data.parent;
  					currentReads = keyReads.slice(keyReads.length - 1);
  				} else {
  					ObservationRecorder.addMany(observes);
  				}
  
  				return {
  					scope: currentScope,
  					rootObserve: currentObserve,
  					value: data.value,
  					reads: currentReads,
  					thisArg: data.parent,
  					parentHasKey: data.parentHasKey
  				};
  			}
  			// Otherwise, save all observables that were read. If no value
  			// is found, we will observe on all of them.
  			else {
  				undefinedObserves.push.apply(undefinedObserves, observes);
  			}
  
  			currentScope = currentScope._parent;
  		}
  
  		// The **value was not found** in the scope
  		// if not looking for a "special" key, check in can-stache-helpers
  		if (howToRead.shouldLookForHelper) {
  			var helper = this.getHelperOrPartial(keyReads);
  
  			if (helper && helper.value) {
  				// Don't return parent so `.bind` is not used.
  				return {value: helper.value};
  			}
  		}
  
  		// The **value was not found**, return `undefined` for the value.
  		// Make sure we listen to everything we checked for when the value becomes defined.
  		// Once it becomes defined, we won't have to listen to so many things.
  		ObservationRecorder.addMany(undefinedObserves);
  		return {
  			setRoot: currentSetObserve,
  			reads: currentSetReads,
  			value: undefined,
  			noContextAvailable: !readAContext
  		};
  	}