'Apply a JSON patch object and process any resulting events.
Args:
patch (JSON-data) :
The JSON-object containing the patch to apply.
setter (ClientSession or ServerSession or None, optional) :
This is used to prevent "boomerang" updates to Bokeh apps.
(default: None)
In the context of a Bokeh server application, incoming updates
to properties will be annotated with the session that is
doing the updating. This value is propagated through any
subsequent change notifications that the update triggers.
The session can compare the event setter to itself, and
suppress any updates that originate from itself.
Returns:
None'

def apply_json_patch(self, patch, setter=None):

    references_json = patch['references']
    events_json = patch['events']
    references = self._instantiate_references_json(references_json)
    for obj in references.values():
        if (obj._id in self._all_models):
            references[obj._id] = self._all_models[obj._id]
    for event_json in events_json:
        if ('model' in event_json):
            model_id = event_json['model']['id']
            if (model_id in self._all_models):
                references[model_id] = self._all_models[model_id]
    self._initialize_references_json(references_json, references)
    for event_json in events_json:
        if (event_json['kind'] == 'ModelChanged'):
            patched_id = event_json['model']['id']
            if (patched_id not in self._all_models):
                if (patched_id not in self._all_former_model_ids):
                    raise RuntimeError(('Cannot    apply    patch    to    %s    which    is    not    in    the    document' % str(patched_id)))
                else:
                    logger.warn(('Cannot    apply    patch    to    %s    which    is    not    in    the    document    anymore' % str(patched_id)))
                    break
            patched_obj = self._all_models[patched_id]
            attr = event_json['attr']
            value = event_json['new']
            patched_obj.set_from_json(attr, value, models=references, setter=setter)
        elif (event_json['kind'] == 'ColumnsStreamed'):
            source_id = event_json['column_source']['id']
            if (source_id not in self._all_models):
                raise RuntimeError(('Cannot    stream    to    %s    which    is    not    in    the    document' % str(source_id)))
            source = self._all_models[source_id]
            data = event_json['data']
            rollover = event_json['rollover']
            source._stream(data, rollover, setter)
        elif (event_json['kind'] == 'ColumnsPatched'):
            source_id = event_json['column_source']['id']
            if (source_id not in self._all_models):
                raise RuntimeError(('Cannot    apply    patch    to    %s    which    is    not    in    the    document' % str(source_id)))
            source = self._all_models[source_id]
            patches = event_json['patches']
            source.patch(patches, setter)
        elif (event_json['kind'] == 'RootAdded'):
            root_id = event_json['model']['id']
            root_obj = references[root_id]
            self.add_root(root_obj, setter)
        elif (event_json['kind'] == 'RootRemoved'):
            root_id = event_json['model']['id']
            root_obj = references[root_id]
            self.remove_root(root_obj, setter)
        elif (event_json['kind'] == 'TitleChanged'):
            self._set_title(event_json['title'], setter)
        else:
            raise RuntimeError(('Unknown    patch    event    ' + repr(event_json)))
