docs: function (func, options) {
  				options = extend({
  					context: root, // what to equate `this` to
  					run_on_create: true, // whether it should run immediately
  					pause_while_running: false, // whether to allow the function to be called recursively (indirectly)
  					priority: false,
  					on_destroy: false // a function to call when this liven function is destroyed
  				}, options);
  
  				//Make constraint-aware values just by calling func in a constraint
  				var node = new Constraint(func, {
  					context: options.context,
  					cache_value: false,
  					auto_add_outgoing_dependencies: false,
  					run_on_add_listener: false
  				});
  
  				// check if running
  				var paused = false;
  				var do_get;
  
  				var invalidate = function() {
  					node.invalidate();
  				};
  
  				// Destroy the node and make sure no memory is allocated
  				var destroy = function (silent) {
  					if(options.on_destroy) {
  						options.on_destroy.call(options.context, silent);
  					}
  					node.destroy(silent);
  				};
  
  				// Stop changing and remove it from the event queue if necessary
  				var pause = function () {
  					if(paused === false) {
  						paused = true;
  						node.offChange(do_get);
  						return true; // successfully paused
  					}
  					return false;
  				};
  
  				// Re-add to the event queue
  				var resume = function () {
  					if(paused === true) {
  						paused = false;
  						node.onChangeWithPriority(options.priority, do_get);
  						if(options.run_on_create !== false) {
  							if (constraint_solver.semaphore >= 0) {
  								node.get(false);
  							} else {
  								each(node._changeListeners, constraint_solver.add_in_call_stack, constraint_solver);
  							}
  						}
  						return true; // successfully resumed
  					}
  					return false;
  				};
  
  				// The actual getter, will call the constraint's getter
  				do_get = function () {
  					if (options.pause_while_running) {
  						pause();
  					}
  					node.get();
  					if (options.pause_while_running) {
  						resume();
  					}
  				};
  
  				// When the value changes, call do_get
  				node.onChangeWithPriority(options.priority, do_get);
  
  				var rv = {
  					destroy: destroy,
  					pause: pause,
  					resume: resume,
  					run: function(arg0) {
  						do_get(arg0);
  						return this;
  					},
  					invalidate: invalidate,
  					_constraint: node // for debugging purposes
  				};
  
  				if(options.run_on_create !== false) {
  					if (constraint_solver.semaphore >= 0) {
  						node.get(false);
  					} else {
  						each(node._changeListeners, constraint_solver.add_in_call_stack, constraint_solver);
  					}
  				}
  
  				return rv;
  			}