public static void save(final String filename) throws IOException {
   final FileOutputStream fos = FileHelper.createFileOutputStream(filename);
   final OutputBitStream ostream = new OutputBitStream(fos);
   ostream.writeInt(ElementPropertiesLibrary.m_elements.size());
   final TIntObjectIterator<ElementProperties> iter =
       ElementPropertiesLibrary.m_elements.iterator();
   for (int i = ElementPropertiesLibrary.m_elements.size(); i > 0; --i) {
     iter.advance();
     iter.value().save(ostream);
   }
   ostream.close();
 }
  /**
   * Iterate over the map, and ensure that if the same string is in the cache, that the entry refers
   * to the cached entry, rather than a new instance.
   *
   * @param stringMap
   */
  public void mergeStrings(TIntObjectHashMap<String> stringMap) {

    if (stringMap == null) return;
    // FIXME: Investigate using String.intern()  what's it's overhead if we
    // do it on all strings.

    // FIXME: Keep track of which integer keys (they should be 0-255) merge well and which don't,
    // by tracking successes
    for (TIntObjectIterator<String> it = stringMap.iterator(); it.hasNext(); ) {
      it.advance();
      int key = it.key();
      assert key < 256;

      // Eliminate poor merging strings
      // FIXME: should also remove existing by having sep cache per key, which
      // we can just remove once can see it's a problem.  For now, we
      // just stop after it seems that we've got no dupls
      if (strFailuresByKey[key] > 5000 && strSuccessesByKey[key] < strFailuresByKey[key]) {
        continue; // if after 5000 failures, we don't have more successes
      }

      String possDupl = it.value();
      String cachedString = stringCache.get(possDupl);
      if (cachedString != null) {
        it.setValue(cachedString); // If have one cached, use it
        strSuccessesByKey[key]++;
      } else {
        stringCache.put(possDupl, possDupl);
        strFailuresByKey[key]++;
      }
    }
  }