text: var observable = function(el) {
  
    /**
     * Extend the original object or create a new empty one
     * @type { Object }
     */
  
    el = el || {}
  
    /**
     * Private variables
     */
    var callbacks = {},
      slice = Array.prototype.slice
  
    /**
     * Private Methods
     */
  
    /**
     * Helper function needed to get and loop all the events in a string
     * @param   { String }   e - event string
     * @param   {Function}   fn - callback
     */
    function onEachEvent(e, fn) {
      var es = e.split(' '), l = es.length, i = 0, name, indx
      for (; i < l; i++) {
        name = es[i]
        indx = name.indexOf('.')
        if (name) fn( ~indx ? name.substring(0, indx) : name, i, ~indx ? name.slice(indx + 1) : null)
      }
    }
  
    /**
     * Public Api
     */
  
    // extend the el object adding the observable methods
    Object.defineProperties(el, {
      /**
       * Listen to the given space separated list of `events` and
       * execute the `callback` each time an event is triggered.
       * @param  { String } events - events ids
       * @param  { Function } fn - callback function
       * @returns { Object } el
       */
      on: {
        value: function(events, fn) {
          if (typeof fn != 'function')  return el
  
          onEachEvent(events, function(name, pos, ns) {
            (callbacks[name] = callbacks[name] || []).push(fn)
            fn.typed = pos > 0
            fn.ns = ns
          })
  
          return el
        },
        enumerable: false,
        writable: false,
        configurable: false
      },
  
      /**
       * Removes the given space separated list of `events` listeners
       * @param   { String } events - events ids
       * @param   { Function } fn - callback function
       * @returns { Object } el
       */
      off: {
        value: function(events, fn) {
          if (events == '*' && !fn) callbacks = {}
          else {
            onEachEvent(events, function(name, pos, ns) {
              if (fn || ns) {
                var arr = callbacks[name]
                for (var i = 0, cb; cb = arr && arr[i]; ++i) {
                  if (cb == fn || ns && cb.ns == ns) arr.splice(i--, 1)
                }
              } else delete callbacks[name]
            })
          }
          return el
        },
        enumerable: false,
        writable: false,
        configurable: false
      },
  
      /**
       * Listen to the given space separated list of `events` and
       * execute the `callback` at most once
       * @param   { String } events - events ids
       * @param   { Function } fn - callback function
       * @returns { Object } el
       */
      one: {
        value: function(events, fn) {
          function on() {
            el.off(events, on)
            fn.apply(el, arguments)
          }
          return el.on(events, on)
        },
        enumerable: false,
        writable: false,
        configurable: false
      },
  
      /**
       * Execute all callback functions that listen to
       * the given space separated list of `events`
       * @param   { String } events - events ids
       * @returns { Object } el
       */
      trigger: {
        value: function(events) {
  
          // getting the arguments
          var arglen = arguments.length - 1,
            args = new Array(arglen),
            fns
  
          for (var i = 0; i < arglen; i++) {
            args[i] = arguments[i + 1] // skip first argument
          }
  
          onEachEvent(events, function(name, pos, ns) {
  
            fns = slice.call(callbacks[name] || [], 0)
  
            for (var i = 0, fn; fn = fns[i]; ++i) {
              if (fn.busy) continue
              fn.busy = 1
              if (!ns || fn.ns == ns) fn.apply(el, fn.typed ? [name].concat(args) : args)
              if (fns[i] !== fn) { i-- }
              fn.busy = 0
            }
  
            if (callbacks['*'] && name != '*')
              el.trigger.apply(el, ['*', name].concat(args))
  
          })
  
          return el
        },
        enumerable: false,
        writable: false,
        configurable: false
      }
    })
  
    return el
  
  }
  