def sync(self, obj_to_sync, cascade=False):
        """ syncs a given object to the server (updates or creates a new one).

        cascade:    True/False

        Arguments:

        obj_to_sync:a python object to sync. If an object has gnode attribute,
                    it means it will be updated on the server. If no gnode
                    attribute is found a new object will be submitted.
        cascade:    sync all children recursively (True/False)
        """
        supp_models = [m for k, m in models_map.items() if \
            not k in ['property', 'value']]
        if not obj_to_sync.__class__ in supp_models:
            raise TypeError('Objects of that type are not supported.')

        processed = [] # collector of permalinks of processed objects
        to_clean = [] # collector of ids of objects to clean parent
        stack = [ obj_to_sync ] # a stack of objects to sync

        self._cache.add_object(obj_to_sync) # if not yet there

        while len( stack ) > 0:

            obj = stack[0] # take first object from stack
            success = False # flag to indicate success of the syncing
            cls = self._meta.get_type_by_obj( obj ) # type of the object, like 'segment'

            # bloody workaround for duplications because of NEO
            obj_descr = self._meta.get_gnode_descr(obj)
            if obj_descr and obj_descr['permalink'] in processed:
                stack.remove( obj )
                continue

            # 1. validate class type
            if not obj.__class__ in supported_models:
                # skip this object completely
                stack.remove( obj )
                print_status('Object %s is not supported.\n' % cut_to_render( obj.__repr__() ))
                continue

            # 2. pre-push new/changed array data to the server (+put in cache)
            # data_refs is a dict like {'signal': 'http://host:/neo/signal/148348', ...}
            try:
                data_refs = self.__push_data_from_obj( obj )
            except (errors.FileUploadError, errors.UnitsError), e:
                # skip this object completely
                stack.remove( obj )
                print_status('%s skipped: %s\n' % (cut_to_render(obj.__repr__(), 15), str(e)))
                continue

            # 3. pre-sync related metadata if exists (+put in cache)
            if hasattr(obj, 'metadata'):

                metadata = getattr(obj, 'metadata')
                if isinstance(metadata, Metadata):

                    to_sync = []
                    for name, prp in metadata.__dict__.items():
                        if prp.value:
                            if not self._meta.get_gnode_descr(prp.value):
                                to_sync.insert(0, prp.value) # sync value if never synced

                            if not self._meta.get_gnode_descr(prp):
                                to_sync.insert(0, prp) # sync property if never synced
                                if not prp.parent:
                                    print_status('Cannot sync %s for %s: section is not defined.\n' % \
                                        (name, cut_to_render( obj.__repr__() )))
                                    stack.remove( prp )
                                    continue # move to other property

                                if not self._meta.get_gnode_descr(prp.parent):
                                    to_sync.insert(0, prp.parent) # sync parent section

                    if to_sync: # sync what's needed first
                        stack = to_sync + stack
                        continue

            # 4. sync main object
            try:
                json_obj = Serializer.serialize(obj, self._meta, data_refs)

                # TODO ideally the JSON object representation should be unique
                # and this code excluded
                for k in list( json_obj['fields'].keys() ):
                    if k.endswith('_set') or k == 'shared_with':
                        json_obj['fields'].pop( k, None )

                raw_json = self._remote.save( json_obj )

                if not raw_json == 304:
                    # update local in-memory object with newly acquired params
                    self._meta.set_gnode_descr(obj, raw_json)

                # a list of children in the gnode attribute in all parent 
                # objects for obj must be updated with a newly synced child. it 
                # should be done here, not at the end of the sync, to keep 
                # objects updated in case the sync fails.
                Serializer.update_parent_children(obj, self._meta)

                success = True
                obj_descr = self._meta.get_gnode_descr(obj)
                processed.append( obj_descr['permalink'] )
                print_status('Object at %s synced.' % obj_descr['location'])

            except (errors.UnitsError, errors.ValidationError, \
                errors.SyncFailed, errors.BadRequestError), e:
                print_status('%s skipped: %s\n' % (cut_to_render(obj.__repr__(), 20), str(e)))