public static long getSeed(String streamId, long masterSeed) {
    MessageDigest md5 = md5Holder.get();
    md5.reset();
    //'/' : make sure that we don't get the same str from ('11',0) and ('1',10)
    // We could have fed the bytes of masterSeed one by one to md5.update()
    // instead
    String str = streamId + '/' + masterSeed;
    byte[] digest = md5.digest(str.getBytes(StandardCharsets.UTF_8));
    // Create a long from the first 8 bytes of the digest
    // This is fine as MD5 has the avalanche property.
    // Paranoids could have XOR folded the other 8 bytes in too. 
    long seed = 0;
    for (int i=0; i<8; i++) {
      seed = (seed<<8) + ((int)digest[i]+128);
    }
    return seed;
  }
@Test
  public void testSeedGeneration() {
    long masterSeed1 = 42;
    long masterSeed2 = 43;
    
    assertTrue("Deterministic seeding",
        getSeed("stream1", masterSeed1) == getSeed("stream1", masterSeed1));
    assertTrue("Deterministic seeding",
        getSeed("stream2", masterSeed2) == getSeed("stream2", masterSeed2));
    assertTrue("Different streams", 
        getSeed("stream1", masterSeed1) != getSeed("stream2", masterSeed1));
    assertTrue("Different master seeds",
        getSeed("stream1", masterSeed1) != getSeed("stream1", masterSeed2));
  }