text: 'use strict';
  
  define(function() {
    function unobserve(_eventHandlers, prop, handler) {
      // arguments in reverse order to support .bind(handler) for the
      // unbind from all case
      function removeHandler(handler, prop) {
        var handlers = _eventHandlers[prop];
        if (!handlers) {
          return;
        }
        var index = handlers.indexOf(handler);
        if (index >= 0) {
          handlers.splice(index, 1);
        }
      }
  
      if (typeof prop === 'function') {
        // (handler) -- remove from every key in _eventHandlers
        Object.keys(_eventHandlers).forEach(removeHandler.bind(null, prop));
      } else if (handler) {
        // (prop, handler) -- remove handler from the specific prop
        removeHandler(handler, prop);
      } else if (prop in _eventHandlers) {
        // (prop) -- otherwise remove all handlers for property
        _eventHandlers[prop] = [];
      }
    }
  
    /*
     * An Observable is able to notify its property change. It is initialized by
     * an ordinary object.
     */
    function Observable(obj) {
      var _eventHandlers = {};
      var _observable = {
        observe: function o_observe(p, handler) {
          /*
           * We should check if _observable[_p] exists. Since _observable[_p] is
           * created along with _eventHandlers[p], here we simply check
           * _eventHandlers[p].
           */
          var handlers = _eventHandlers[p];
          if (handlers) {
            handlers.push(handler);
          }
        },
        /**
         * unobserve([prop], handler) - remove handler from observeable callbacks
         */
        unobserve: unobserve.bind(null, _eventHandlers)
      };
  
      var _getFunctionTemplate = function(p) {
        return function() {
          return _observable['_' + p];
        };
      };
  
      var _setFunctionTemplate = function(p) {
        return function(value) {
          var oldValue = _observable['_' + p];
          if (oldValue !== value) {
            _observable['_' + p] = value;
            var handlers = _eventHandlers[p];
            handlers.forEach(function(handler) {
              handler(value, oldValue);
            });
          }
        };
      };
  
      /*
       * Iterate all properties in the object and create corresponding getter and
       * setter for them.
       */
      for (var p in obj) {
        // If p is a function, simply add it to the observable.
        if (typeof obj[p] === 'function') {
          _observable[p] = obj[p];
          continue;
        }
  
        _eventHandlers[p] = [];
  
        Object.defineProperty(_observable, '_' + p, {
          value: obj[p],
          writable: true
        });
  
        Object.defineProperty(_observable, p, {
          enumerable: true,
          get: _getFunctionTemplate(p),
          set: _setFunctionTemplate(p)
        });
      }
  
      return _observable;
    }
  
    return Observable;
  });
  