code: func parseJavaProfile(b []byte) (*Profile, error) {
  	h := bytes.SplitAfterN(b, []byte("\n"), 2)
  	if len(h) < 2 {
  		return nil, errUnrecognized
  	}
  
  	p := &Profile{
  		PeriodType: &ValueType{},
  	}
  	header := string(bytes.TrimSpace(h[0]))
  
  	var err error
  	var pType string
  	switch header {
  	case "--- heapz 1 ---":
  		pType = "heap"
  	case "--- contentionz 1 ---":
  		pType = "contention"
  	default:
  		return nil, errUnrecognized
  	}
  
  	if b, err = parseJavaHeader(pType, h[1], p); err != nil {
  		return nil, err
  	}
  	var locs map[uint64]*Location
  	if b, locs, err = parseJavaSamples(pType, b, p); err != nil {
  		return nil, err
  	}
  	if err = parseJavaLocations(b, locs, p); err != nil {
  		return nil, err
  	}
  
  	// Strip out addresses for better merge.
  	if err = p.Aggregate(true, true, true, true, false); err != nil {
  		return nil, err
  	}
  
  	return p, nil
  }
docs: // parseJavaProfile returns a new profile from heapz or contentionz
  // data. b is the profile bytes after the header.