public Object down(Event evt) {

        switch(evt.getType()) {

            case Event.VIEW_CHANGE:
                handleViewChange(evt.getArg());
                break;

            case Event.GET_STATE:
                StateTransferInfo info=evt.getArg();
                Address target=info.target;

                if(Objects.equals(target, local_addr)) {
                    log.error("%s: cannot fetch state from myself", local_addr);
                    target=null;
                }
                if(target == null)
                    target=determineCoordinator();

                if(target == null) {
                    log.debug("%s: first member (no state)", local_addr);
                    up_prot.up(new Event(Event.STATE_TRANSFER_INPUTSTREAM_CLOSED, new StateTransferResult()));
                }
                else {
                    state_provider=target;
                    Message state_req=new Message(target).putHeader(this.id, new StateHeader(StateHeader.STATE_REQ))
                      .setFlag(Message.Flag.SKIP_BARRIER, Message.Flag.DONT_BUNDLE, Message.Flag.OOB);
                    log.debug("%s: asking %s for state", local_addr, target);
                    down_prot.down(state_req);
                }
                return null; // don't pass down any further !

            case Event.CONFIG:
                handleConfig(evt.getArg());
                break;

            case Event.SET_LOCAL_ADDRESS:
                local_addr=evt.getArg();
                break;
        }

        return down_prot.down(evt); // pass on to the layer below us
    }