Sort Table in place, using given fields as sort key.
           @param key: if this is a string, it is a comma-separated list of field names,
              optionally followed by 'desc' to indicate descending sort instead of the 
              default ascending sort; if a list or tuple, it is a list or tuple of field names
              or field names with ' desc' appended; if it is a function, then it is the 
              function to be used as the sort key function
           @param reverse: (default=False) set to True if results should be in reverse order
           @type reverse: bool
           @return: self

def sort(self, key, reverse=False):
        """Sort Table in place, using given fields as sort key.
           @param key: if this is a string, it is a comma-separated list of field names,
              optionally followed by 'desc' to indicate descending sort instead of the 
              default ascending sort; if a list or tuple, it is a list or tuple of field names
              or field names with ' desc' appended; if it is a function, then it is the 
              function to be used as the sort key function
           @param reverse: (default=False) set to True if results should be in reverse order
           @type reverse: bool
           @return: self
        """
        if isinstance(key, (basestring, list, tuple)):
            if isinstance(key, basestring):
                attrdefs = [s.strip() for s in key.split(',')]
                attr_orders = [(a.split()+['asc', ])[:2] for a in attrdefs]
            else:
                # attr definitions were already resolved to a sequence by the caller
                if isinstance(key[0], basestring):
                    attr_orders = [(a.split()+['asc', ])[:2] for a in key]
                else:
                    attr_orders = key
            attrs = [attr for attr, order in attr_orders]

            # special optimization if all orders are ascending or descending
            if all(order == 'asc' for attr, order in attr_orders):
                self.obs.sort(key=attrgetter(*attrs), reverse=reverse)
            elif all(order == 'desc' for attr, order in attr_orders):
                self.obs.sort(key=attrgetter(*attrs), reverse=not reverse)
            else:
                # mix of ascending and descending sorts, have to do succession of sorts
                # leftmost attr is the most primary sort key, so reverse attr_orders to do
                # succession of sorts from right to left
                do_all(self.obs.sort(key=attrgetter(attr), reverse=(order == "desc"))
                       for attr, order in reversed(attr_orders))
        else:
            # sorting given a sort key function
            keyfn = key
            self.obs.sort(key=keyfn, reverse=reverse)
        return self