code: public void merge(Map<Address, View> views) {
          if(views == null || views.isEmpty()) {
              log.warn("the views passed with the MERGE event were empty (or null); ignoring MERGE event");
              return;
          }
  
          if(View.sameViews(views.values())) {
              log.debug("MERGE event is ignored because of identical views: %s", Util.printListWithDelimiter(views.values(), ", "));
              return;
          }
  
          if(isMergeInProgress()) {
              log.trace("%s: merge is already running (merge_id=%s)", gms.local_addr, merge_id);
              return;
          }
  
          Address merge_leader=determineMergeLeader(views);
          if(merge_leader == null)
              return;
  
          if(merge_leader.equals(gms.local_addr)) {
              log.debug("%s: I will be the merge leader. Starting the merge task. Views: %s", gms.local_addr, views);
              merge_task.start(views);
          }
          else
              log.trace("%s: I'm not the merge leader, waiting for merge leader (%s) to start merge", gms.local_addr, merge_leader);
      }
docs: Invoked upon receiving a MERGE event from the MERGE layer. Starts the merge protocol.
  See description of protocol in DESIGN.
  @param views A List of <em>different</em> views detected by the merge protocol, keyed by sender