docs: function(options) {
  	this.options = options;
  	this.targets = options.targets; // the DOM nodes
  	var setter = options.setter, // a function that sets the attribute value
  		getter = options.getter, // a function that gets the attribute value
  		init_val = options.init_val, // the value of the attribute before the binding was set
  		curr_value, // used in live fn
  		last_value, // used in live fn
  		old_targets = [], // used in live fn
  		do_update = function() {
  			this._timeout_id = false; // Make it clear that I don't have a timeout set
  			var new_targets = filter(get_dom_array(this.targets), isAnyElement); // update the list of targets
  
  			if(has(options, "onChange")) {
  				options.onChange.call(this, curr_value, last_value);
  			}
  
  			// For every target, update the attribute
  			each(new_targets, function(target) {
  				setter.call(this, target, curr_value, last_value);
  			}, this);
  
  			// track the last value so that next time we call diff
  			last_value = curr_value;
  		};
  	this._throttle_delay = false; // Optional throttling to improve performance
  	this._timeout_id = false; // tracks the timeout that helps throttle
  
  	if(isFunction(init_val)) { // If init_val is a getter, call it on the first element
  		last_value = init_val(get_dom_array(this.targets[0]));
  	} else { // Otherwise, just take it as is
  		last_value = init_val;
  	}
  
  	this.$live_fn = cjs.liven(function() {
  		curr_value = getter(); // get the value once and inside of live fn to make sure a dependency is added
  
  		if(this._throttle_delay) { // We shouldn't update values right away
  			if(!this._timeout_id) { // If there isn't any timeout set yet, then set a timeout to delay the call to do update
  				this._timeout_id = sTO(bind(do_update, this), this._throttle_delay);
  			}
  		} else { // we can update the value right away if no throttle delay is set
  			do_update.call(this);
  		}
  	}, {
  		context: this
  	});
  }