code: package org.gridkit.jvmtool.event;
  
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  import java.util.SortedMap;
  import java.util.TreeMap;
  
  public class SimpleTagCollection implements TagCollection {
  
      private SortedMap<Tag, Tag> tags = new TreeMap<Tag, Tag>();
  
      public SimpleTagCollection() {
      }
  
      public SimpleTagCollection(TagCollection that) {
          for(String key: that) {
              for(String tag: that.tagsFor(key)) {
                  put(key, tag);
              }
          }
      }
  
      protected SimpleTagCollection(Iterable<Tag> tags) {
          for(Tag t: tags) {
              this.tags.put(t, t);
          }
      }
  
      @Override
      public Iterator<String> iterator() {
          return new KeyIterator(tags.keySet().iterator());
      }
  
      @Override
      public Iterable<String> tagsFor(final String key) {
          return new Iterable<String>() {
              @Override
              public Iterator<String> iterator() {
                  return new TagIterator(key, tags.tailMap(new Tag(key, "")).keySet().iterator());
              }
          };
      }
  
      @Override
      public String firstTagFor(String key) {
          SortedMap<Tag, Tag> tail = tags.tailMap(new Tag(key, ""));
          if (!tail.isEmpty()) {
              Tag f = tail.firstKey();
              if (key.equals(f.tagKey)) {
                  return f.tagValue;
              }
          }
          return null;
      }
  
      @Override
      public boolean contains(String key, String tag) {
          if (key == null) {
              throw new NullPointerException("'key' is null");
          }
          if (tag == null) {
              throw new NullPointerException("'tag' is null");
          }
          return tags.containsKey(new Tag(key, tag));
      }
  
      @Override
      public SimpleTagCollection clone() {
          return new SimpleTagCollection(tags.keySet());
      }
  
      public void put(String key, String tag) {
          if (key == null) {
              throw new NullPointerException("'key' is null");
          }
          if (tag == null) {
              throw new NullPointerException("'tag' is null");
          }
          Tag t = new Tag(key, tag);
          tags.put(t, t);
      }
  
      public void putAll(TagCollection that) {
          for(String key: that) {
              for(String tag: that.tagsFor(key)) {
                  put(key, tag);
              }
          }
      }
  
      public void remove(String key) {
          if (key == null) {
              throw new NullPointerException("'key' is null");
          }
          Iterator<Tag> it = tags.tailMap(new Tag(key, "")).keySet().iterator();
          while(it.hasNext()) {
              Tag t = it.next();
              if (t.tagKey.equals(key)) {
                  it.remove();
              }
              else {
                  break;
              }
          }
      }
  
      public void remove(String key, String tag) {
          if (key == null) {
              throw new NullPointerException("'key' is null");
          }
          if (tag == null) {
              throw new NullPointerException("'tag' is null");
          }
          Tag t = new Tag(key, tag);
          tags.remove(t);
      }
  
      public void clear() {
          tags.clear();
      }
  
      private static class KeyIterator implements Iterator<String> {
  
          private final Iterator<Tag> iterator;
          private String nextKey = null;
  
          public KeyIterator(Iterator<Tag> tags) {
              iterator = tags;
              seekNext();
          }
  
          private void seekNext() {
              while(iterator.hasNext()) {
                  Tag tag = iterator.next();
                  if (!tag.tagKey.equals(nextKey)) {
                      nextKey = tag.tagKey;
                      return;
                  }
              }
              nextKey = null;
          }
  
          public boolean hasNext() {
              return nextKey != null;
          }
  
          @Override
          public String next() {
              if (!hasNext()) {
                  throw new NoSuchElementException();
              }
              String tagKey = nextKey;
              seekNext();
              return tagKey;
          }
  
          @Override
          public void remove() {
              throw new UnsupportedOperationException();
          }
      }
  
      private static class TagIterator implements Iterator<String> {
  
          private final String key;
          private final Iterator<Tag> iterator;
          private String nextTag;
  
          public TagIterator(String key, Iterator<Tag> iterator) {
              this.key = key;
              this.iterator = iterator;
              seekNext();
          }
  
          private void seekNext() {
              while(iterator.hasNext()) {
                  Tag tag = iterator.next();
                  if (!key.equals(tag.tagKey)) {
                      break;
                  }
                  nextTag = tag.tagValue;
                  return;
              }
              nextTag = null;
          }
  
          @Override
          public boolean hasNext() {
              return nextTag != null;
          }
  
          @Override
          public String next() {
              if (!hasNext()) {
                  throw new NoSuchElementException();
              }
              String tag = nextTag;
              seekNext();
              return tag;
          }
  
          @Override
          public void remove() {
              throw new UnsupportedOperationException();
          }
      }
  
      public String toString() {
          return tags.keySet().toString();
      }
  
      private static class Tag implements Comparable<Tag> {
  
          final String tagKey;
          final String tagValue;
  
          public Tag(String tagKey, String tagValue) {
              this.tagKey = tagKey;
              this.tagValue = tagValue;
          }
  
          @Override
          public int compareTo(Tag that) {
              int n = tagKey.compareTo(that.tagKey);
              if (n == 0) {
                  n = tagValue.compareTo(that.tagValue);
              }
              return n;
          }
  
          public String toString() {
              return tagKey + ":" + tagValue;
          }
      }
  }
  