code: func Hash(spec *vpython.Spec, rt *vpython.Runtime, extra ...string) string {
  	mustMarshal := func(msg proto.Message) []byte {
  		data, err := proto.Marshal(msg)
  		if err != nil {
  			panic(fmt.Errorf("failed to marshal proto: %v", err))
  		}
  		return data
  	}
  	specData := mustMarshal(spec)
  	rtData := mustMarshal(rt)
  
  	mustWrite := func(v int, err error) {
  		if err != nil {
  			panic(fmt.Errorf("impossible: %s", err))
  		}
  	}
  
  	hash := sha256.New()
  	for _, s := range extra {
  		mustWrite(fmt.Fprintf(hash, "%s:", s))
  	}
  	mustWrite(fmt.Fprintf(hash, "%s:", vpython.Version))
  	mustWrite(hash.Write(specData))
  	mustWrite(hash.Write([]byte(":")))
  	mustWrite(hash.Write(rtData))
  	return hex.EncodeToString(hash.Sum(nil))
  }
docs: // Hash hashes the contents of the supplied "spec" and "rt" and returns the
  // result as a hex-encoded string.
  //
  // If not empty, the contents of extra are prefixed to hash string. This can
  // be used to factor additional influences into the spec hash.