code: func generateDatasetItem(cache []uint32, index uint32, keccak512 hasher) []byte {
  	// Calculate the number of theoretical rows (we use one buffer nonetheless)
  	rows := uint32(len(cache) / hashWords)
  
  	// Initialize the mix
  	mix := make([]byte, hashBytes)
  
  	binary.LittleEndian.PutUint32(mix, cache[(index%rows)*hashWords]^index)
  	for i := 1; i < hashWords; i++ {
  		binary.LittleEndian.PutUint32(mix[i*4:], cache[(index%rows)*hashWords+uint32(i)])
  	}
  	keccak512(mix, mix)
  
  	// Convert the mix to uint32s to avoid constant bit shifting
  	intMix := make([]uint32, hashWords)
  	for i := 0; i < len(intMix); i++ {
  		intMix[i] = binary.LittleEndian.Uint32(mix[i*4:])
  	}
  	// fnv it with a lot of random cache nodes based on index
  	for i := uint32(0); i < datasetParents; i++ {
  		parent := fnv(index^i, intMix[i%16]) % rows
  		fnvHash(intMix, cache[parent*hashWords:])
  	}
  	// Flatten the uint32 mix into a binary one and return
  	for i, val := range intMix {
  		binary.LittleEndian.PutUint32(mix[i*4:], val)
  	}
  	keccak512(mix, mix)
  	return mix
  }
docs: // generateDatasetItem combines data from 256 pseudorandomly selected cache nodes,
  // and hashes that to compute a single dataset node.