def observe(cls, *args, **kwargs):
        """
        Mark a method as receiving notifications. Comes in two flavours:

        .. method:: observe(name, **types)
           :noindex:

           A decorator living in the class. Can be applied more than once to
           the same method, provided the names differ.

           *name* is the property we want to be notified about as a
           string.

           .. Note::

              Alternatively, *name* can be a pattern for matching
              property names, meaning it can contain wildcards
              character like in module `fnmatch
              <http://docs.python.org/library/fnmatch.html>`_ in
              Python library. However, if wildcards are used in name,
              only *one* `observe` can be used for a given
              notification method, or else `ValueError` exception is
              raised when the Observer class is instantiated.

              .. versionadded:: 1.99.2

           *types* are boolean values denoting the types of
           notifications desired. At least one of the following has to be
           passed as True: assign, before, after, signal.

           Excess keyword arguments are passed to the method as part of the
           info dictionary.

        .. method:: observe(callable, name, **types)
           :noindex:

           An instance method to define notifications at runtime. Works as
           above.

           *callable* is the method to send notifications to. The effect will
           be as if this had been decorated.

        In all cases the notification method must take exactly three
        arguments: the model object, the name of the property that changed,
        and an :class:`NTInfo` object describing the change.

        .. warning::

           Due to limitation in the dynamic registration (in version
           1.99.1), declarations of dynamic notifications must occur
           before registering self as an observer of the models whose
           properties the notifications are supposed to be
           observing. A hack for this limitation, is to first relieve
           any interesting model before dynamically register the
           notifications, and then re-observe those models.

        .. versionadded:: 1.99.1
        """

        @decorators.good_decorator
        def _decorator(_notified):
            # marks the method with observed properties
            _list = getattr(_notified, Observer._CUST_OBS_, list())
            _list.append((name, kwargs))
            setattr(_notified, Observer._CUST_OBS_, _list)
            return _notified

        # handles arguments
        if args and isinstance(args[0], cls):
            # Used as instance method, for declaring notifications
            # dynamically
            if len(args) != 3:
                raise TypeError("observe() takes exactly three arguments"
                                " when called (%d given)" % len(args))

            self = args[0]
            notified = args[1]
            name = args[2]

            assert isinstance(self, Observer), "Method Observer.observe " \
                "must be called with an Observer instance as first argument"
            if not callable(notified):
                raise TypeError("Second argument of observe() "
                                "must be a callable")
            if not isinstance(name, str):
                raise TypeError("Third argument of observe() must be a string")

            self.__register_notification(name, notified, kwargs)
            return None

        # used statically as decorator
        if len(args) != 1:
            raise TypeError("observe() takes exactly one argument when used"
                            " as decorator (%d given)" % len(args))
        name = args[0]
        if not isinstance(name, str):
            raise TypeError("First argument of observe() must be a string")
        return _decorator