public MenuKey(MMenuContribution mc) {
   super(
       mc.getParentId(),
       mc.getPositionInParent(),
       mc.getTags(),
       (MCoreExpression) mc.getVisibleWhen(),
       mc.getTransientData().get(FACTORY));
   this.contribution = mc;
   mc.setWidget(this);
 }
 public static void mergeContributions(
     ArrayList<MMenuContribution> contributions, ArrayList<MMenuContribution> result) {
   HashMap<MenuKey, ArrayList<MMenuContribution>> buckets =
       new HashMap<MenuKey, ArrayList<MMenuContribution>>();
   trace("mergeContributions size: " + contributions.size(), null); // $NON-NLS-1$
   printContributions(contributions);
   // first pass, sort by parentId?position,scheme,visibleWhen
   for (MMenuContribution contribution : contributions) {
     MenuKey key = getKey(contribution);
     ArrayList<MMenuContribution> slot = buckets.get(key);
     if (slot == null) {
       slot = new ArrayList<MMenuContribution>();
       buckets.put(key, slot);
     }
     slot.add(contribution);
   }
   Iterator<MMenuContribution> i = contributions.iterator();
   while (i.hasNext() && !buckets.isEmpty()) {
     MMenuContribution contribution = i.next();
     MenuKey key = getKey(contribution);
     ArrayList<MMenuContribution> slot = buckets.remove(key);
     if (slot == null) {
       continue;
     }
     MMenuContribution toContribute = null;
     for (MMenuContribution item : slot) {
       if (toContribute == null) {
         toContribute = item;
         continue;
       }
       Object[] array = item.getChildren().toArray();
       for (int c = 0; c < array.length; c++) {
         MMenuElement me = (MMenuElement) array[c];
         if (!containsMatching(toContribute.getChildren(), me)) {
           toContribute.getChildren().add(me);
         }
       }
     }
     if (toContribute != null) {
       toContribute.setWidget(null);
       result.add(toContribute);
     }
   }
   trace("mergeContributions: final size: " + result.size(), null); // $NON-NLS-1$
 }