ronantakizawa/codereview-bench huggingface dataset:
Repository: moby/moby
File: daemon/server/router/system/info_response_test.go (Go)

Code before:
			info: &infoResponse{
				Info: &system.Info{},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)
				for k, v := range expected {
					assert.Check(t, !strings.Contains(string(data), v), fmt.Sprintf("Legacy field %q should be omitted in output: %s", k, string(data)))
				}
			},
		},
		{
			name: "with legacy fields",
			info: &infoResponse{
				Info: &system.Info{
					RegistryConfig: &registry.ServiceConfig{
						ExtraFields: map[string]any{
							"AllowNondistributableArtifactsCIDRs":     json.RawMessage(nil),
							"AllowNondistributableArtifactsHostnames": json.RawMessage(nil),
						},
					},
				},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)
				for k, v := range expected {
					assert.Check(t, strings.Contains(string(data), v), fmt.Sprintf("Expected legacy field %q to be included in the output: %s", k, string(data)))
				}
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			data, err := json.MarshalIndent(tt.info, "", "  ")
			tt.assert(t, data, err)
		})
	}
}


Review comment (bug):
I think `assert.Check(t, is.Contains(string(data), v))` may also work for strings, and print the output when failing

(writing from my phone so can't verify what it looks like)

Code after:
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)

				var resp map[string]any
				err = json.Unmarshal(data, &resp)
				assert.NilError(t, err)

				rc, ok := resp["RegistryConfig"]
				assert.Check(t, ok)

				for _, v := range expected {
					assert.Check(t, !is.Contains(rc, v)().Success())
				}
			},
		},
		{
			name: "with legacy fields",
			info: &infoResponse{
				Info: &system.Info{
					RegistryConfig: &registry.ServiceConfig{
						ExtraFields: map[string]any{
							"AllowNondistributableArtifactsCIDRs":     json.RawMessage(nil),
							"AllowNondistributableArtifactsHostnames": json.RawMessage(nil),
						},
					},
				},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)

				var resp map[string]any
				err = json.Unmarshal(data, &resp)
				assert.NilError(t, err)

				rc, ok := resp["RegistryConfig"]
				assert.Check(t, ok)

				for _, v := range expected {
					assert.Check(t, is.Contains(rc, v))
				}
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			data, err := json.MarshalIndent(tc.info, "", "  ")
			tc.assert(t, data, err)
		})
	}
}
Repository: moby/moby
File: daemon/server/router/system/info_response_test.go (Go)

Code before:
	}
}

// TestMarshalRegistryConfigLegacyFields verifies extra fields in the registry config
// field in the info response are serialized if they are not empty.
// This is used for backwards compatibility for API versions < 1.47.
func TestMarshalRegistryConfigLegacyFields(t *testing.T) {
	expected := []string{
		`"AllowNondistributableArtifactsCIDRs": null`,
		`"AllowNondistributableArtifactsHostnames": null`,
	}

	tests := []struct {
		name   string
		info   *infoResponse
		assert func(t *testing.T, data []byte, err error)
	}{
		{
			name: "without legacy fields",
			info: &infoResponse{
				Info: &system.Info{},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)
				for _, v := range expected {
					assert.Check(t, !is.Contains(string(data), v)().Success())
				}
			},
		},
		{
			name: "with legacy fields",
			info: &infoResponse{
				Info: &system.Info{
					RegistryConfig: &registry.ServiceConfig{
						ExtraFields: map[string]any{
							"AllowNondistributableArtifactsCIDRs":     json.RawMessage(nil),
							"AllowNondistributableArtifactsHostnames": json.RawMessage(nil),
						},
					},
				},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)
				for _, v := range expected {
					assert.Check(t, is.Contains(string(data), v))
				}
			},
		},
	}

	for _, tc := range tests {

Review comment (suggestion):
String comparisons? As an alternative, you could [unmarshal into a `map[string]any`](https://go.dev/play/p/hVQdLtLwp27) and assert on the presence/absence of map keys.

Code after:
	}
}

// TestMarshalRegistryConfigLegacyFields verifies extra fields in the registry config
// field in the info response are serialized if they are not empty.
// This is used for backwards compatibility for API versions < 1.47.
func TestMarshalRegistryConfigLegacyFields(t *testing.T) {
	expected := []string{"AllowNondistributableArtifactsCIDRs", "AllowNondistributableArtifactsHostnames"}

	tests := []struct {
		name   string
		info   *infoResponse
		assert func(t *testing.T, data []byte, err error)
	}{
		{
			name: "without legacy fields",
			info: &infoResponse{
				Info: &system.Info{},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)

				var resp map[string]any
				err = json.Unmarshal(data, &resp)
				assert.NilError(t, err)

				rc, ok := resp["RegistryConfig"]
				assert.Check(t, ok)

				for _, v := range expected {
					assert.Check(t, !is.Contains(rc, v)().Success())
				}
			},
		},
		{
			name: "with legacy fields",
			info: &infoResponse{
				Info: &system.Info{
					RegistryConfig: &registry.ServiceConfig{
						ExtraFields: map[string]any{
							"AllowNondistributableArtifactsCIDRs":     json.RawMessage(nil),
							"AllowNondistributableArtifactsHostnames": json.RawMessage(nil),
						},
					},
				},
			},
			assert: func(t *testing.T, data []byte, err error) {
				assert.NilError(t, err)

				var resp map[string]any
				err = json.Unmarshal(data, &resp)
Repository: moby/moby
File: api/types/container/container.go (Go)

Code before:
type InspectResponse struct {
	ID              string `json:"Id"`
	Created         string
	Path            string
	Args            []string
	State           *State
	Image           string
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	Platform        string
	MountLabel      string
	ProcessLabel    string
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *HostConfig

	// GraphDriver contains information about the container's graph driver.
	GraphDriver storage.DriverData `json:"GraphDriver,omitempty"`

	// StorageDriver contains information about the container's storage driver.
	StorageDriver storage.Driver `json:"StorageDriver,omitempty"`

	SizeRw          *int64 `json:",omitempty"`
	SizeRootFs      *int64 `json:",omitempty"`
	Mounts          []MountPoint
	Config          *Config
	NetworkSettings *NetworkSettings
	// ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container.
	ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"`
}


Review comment (suggestion):
IMO, this should not be tied to "driver" specifically.

I think a more general "Storage" struct would be better and more future proof.

Currently the only thing we need to store for container is the snapshot for the rootfs of the container.

```go
package container

type Storage struct {
  RootFS  *RootFSStorage `json:",omitempty"`
}
```

Where `RootFSStorage` would be a poor ~man~goopher's union (with 1 variant at the moment):

```go
type RootFSStorage struct {
  Snapshot   *RootFSStorageSnapshot `json:",omitempty"` 
}

type RootFSStorageSnapshot struct {
  SnapshotID string
  SnapshotterName string
}
```


Code after:
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	Platform        string
	MountLabel      string
	ProcessLabel    string
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *HostConfig

	// GraphDriver contains information about the container's graph driver.
	GraphDriver *storage.DriverData `json:"GraphDriver,omitempty"`

	// Storage contains information about the storage used for the container's filesystem.
	Storage *storage.Storage `json:"Storage,omitempty"`

	SizeRw          *int64 `json:",omitempty"`
	SizeRootFs      *int64 `json:",omitempty"`
	Mounts          []MountPoint
	Config          *Config
	NetworkSettings *NetworkSettings
	// ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container.
	ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"`
}
Repository: moby/moby
File: hack/generate-swagger-api.sh (Shell)

Code before:
generate_model types/network --keep-spec-order --additional-initialism=IPAM <<- 'EOT'
	ConfigReference
	EndpointResource
	IPAMStatus
	Network
	NetworkCreateResponse
	NetworkInspect
	NetworkStatus
	NetworkSummary
	NetworkTaskInfo
	PeerInfo
	SubnetStatus
EOT

generate_model types/plugin <<- 'EOT'
	Plugin
	PluginDevice
	PluginEnv
	PluginMount
EOT

generate_model types/storage <<- 'EOT'
	DriverData
	Storage
	RootFSStorage
	RootFSStorageSnapshot
EOT

generate_model types/swarm <<- 'EOT'
	ServiceCreateResponse
	ServiceUpdateResponse
EOT

generate_model types/volume <<- 'EOT'
	Volume
	VolumeCreateOptions
	VolumeListResponse
EOT

#endregion

#region -------- Operations --------

generate_operation --skip-responses --skip-parameters <<- 'EOT'
	Authenticate
	ImageHistory
EOT

#endregion


Review comment (suggestion):
😅 https://github.com/moby/moby/blob/8025c404936b901765628513bf857d8319f1e71f/hack/generate-swagger-api.sh#L28-L36


```suggestion
	RootFSStorage
	RootFSStorageSnapshot
	Storage
```

Code after:
generate_model types/network --keep-spec-order --additional-initialism=IPAM <<- 'EOT'
	ConfigReference
	EndpointResource
	IPAMStatus
	Network
	NetworkCreateResponse
	NetworkInspect
	NetworkStatus
	NetworkSummary
	NetworkTaskInfo
	PeerInfo
	SubnetStatus
EOT

generate_model types/plugin <<- 'EOT'
	Plugin
	PluginDevice
	PluginEnv
	PluginMount
EOT

generate_model types/storage <<- 'EOT'
	DriverData
	RootFSStorage
	RootFSStorageSnapshot
	Storage
EOT

generate_model types/swarm <<- 'EOT'
	ServiceCreateResponse
	ServiceUpdateResponse
EOT

generate_model types/volume <<- 'EOT'
	Volume
	VolumeCreateOptions
	VolumeListResponse
EOT

#endregion

#region -------- Operations --------

generate_operation --skip-responses --skip-parameters <<- 'EOT'
	Authenticate
	ImageHistory
EOT

#endregion
Repository: moby/moby
File: integration/internal/build/build.go (Go)

Code before:

// GetImageIDFromBody reads the image ID from the build response body.
func GetImageIDFromBody(t *testing.T, body io.Reader) string {
	var id string
	dec := json.NewDecoder(body)
	for {
		var jm jsonmessage.JSONMessage
		err := dec.Decode(&jm)
		if err == io.EOF {
			break
		}
		assert.NilError(t, err)
		if jm.Aux == nil {
			continue
		}

		var br build.Result
		if err := json.Unmarshal(*jm.Aux, &br); err == nil {
			if br.ID == "" {
				continue
			}
			id = br.ID
			break
		}
	}
	io.Copy(io.Discard, body)

	assert.Assert(t, id != "", "could not read image ID from build output")
	return id
}


Review comment (suggestion):
If you still need to update; while we're updating; perhaps also explicitly discard the error;

```go
	_, _ = io.Copy(io.Discard, body)
```


Code after:
	})
	return img
}

// GetImageIDFromBody reads the image ID from the build response body.
func GetImageIDFromBody(t *testing.T, body io.Reader) string {
	var id string
	buf := bytes.NewBuffer(nil)
	dec := json.NewDecoder(body)
	for {
		var jm jsonmessage.JSONMessage
		err := dec.Decode(&jm)
		if err == io.EOF {
			break
		}
		assert.NilError(t, err)

		if handled := processBuildkitAux(t, &jm, &id); handled {
			continue
		}

		buf.Reset()
		jm.Display(buf, false)
		if buf.Len() == 0 {
			continue
		}

		t.Log(buf.String())

		if jm.Aux == nil {
			continue
		}

		var br build.Result
		if err := json.Unmarshal(*jm.Aux, &br); err == nil {
			if br.ID == "" {
				continue
			}
			id = br.ID
			continue
		}

		t.Log("Raw Aux", string(*jm.Aux))
	}
	_, _ = io.Copy(io.Discard, body)

	assert.Assert(t, id != "", "could not read image ID from build output")
	return id
}

func processBuildkitAux(t *testing.T, jm *jsonmessage.JSONMessage, id *string) bool {
Repository: moby/moby
File: client/image_pull.go (Go)

Code before:
package client

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"iter"
	"net/url"
	"strings"

	cerrdefs "github.com/containerd/errdefs"
	"github.com/distribution/reference"
	"github.com/moby/moby/client/pkg/jsonmessage"
)

type ImagePullResponse struct {
	io.ReadCloser
}

// Messages decodes the response stream as a sequence of JSONMessages
func (r *ImagePullResponse) Messages() iter.Seq2[*jsonmessage.JSONMessage, error] {
	dec := json.NewDecoder(r.ReadCloser)
	return func(yield func(*jsonmessage.JSONMessage, error) bool) {
		defer r.ReadCloser.Close()
		for {
			var jm jsonmessage.JSONMessage
			if err := dec.Decode(&jm); err != nil {
				if errors.Is(err, io.EOF) {
					break
				}
				if !yield(nil, err) {
					return
				}
			}
			if !yield(&jm, nil) {
				return
			}
		}
	}
}

// ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// Caller can rely on ImagePullResponse#Messages() to monitor pull progress as a sequence of JSONMessages
// otherwise it's up to the caller to handle the [io.ReadCloser] and close it.

Review comment (suggestion):
I think we should make it more explicit -

```suggestion
func (r *ImagePullResponse) JSONMessages() iter.Seq2[*jsonmessage.JSONMessage, error] {
```

In future, I think we should have a better public interface than `JSONMessage` and we wouldn't need to change the signaure of `Messages` then.

Code after:
package client

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"iter"
	"net/url"
	"strings"
	"sync"

	cerrdefs "github.com/containerd/errdefs"
	"github.com/distribution/reference"
	"github.com/moby/moby/client/pkg/jsonmessage"
)

func newImagePullResponse(rc io.ReadCloser) ImagePullResponse {
	return ImagePullResponse{
		rc:    rc,
		close: &sync.Once{},
	}
}

type ImagePullResponse struct {
	rc    io.ReadCloser
	close *sync.Once
}

// Read implements io.ReadCloser
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() error {
	if r.close == nil {
		return nil
	}
	var err error
	r.close.Do(func() {
		if r.rc != nil {
			err = r.rc.Close()
		}
	})
	return err
}
Repository: moby/moby
File: client/image_pull.go (Go)

Code before:
package client

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"iter"
	"net/url"
	"strings"

	cerrdefs "github.com/containerd/errdefs"
	"github.com/distribution/reference"
	"github.com/moby/moby/client/pkg/jsonmessage"
)

type ImagePullResponse struct {
	io.ReadCloser
}

// Messages decodes the response stream as a sequence of JSONMessages
func (r *ImagePullResponse) JSONMessages() iter.Seq2[jsonmessage.JSONMessage, error] {
	dec := json.NewDecoder(r.ReadCloser)
	return func(yield func(jsonmessage.JSONMessage, error) bool) {
		defer r.ReadCloser.Close()
		for {
			var jm jsonmessage.JSONMessage
			err := dec.Decode(&jm)
			if errors.Is(err, io.EOF) {
				break
			}
			if !yield(jm, nil) {
				return
			}
		}
	}
}

// ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// Caller can rely on ImagePullResponse#Messages() to monitor pull progress as a sequence of JSONMessages
// otherwise it's up to the caller to handle the [io.ReadCloser] and close it.

Review comment (suggestion):
```suggestion
	rd io.ReadCloser
```

We should probably make it a concrete field and then implementing the `io.ReadCloser` for the `ImagePullResponse`.

This will also allow us to wrap `Close` method so we don't close the underlying reader twice in cases like:

```go
out, err := ImagePull(...)
...

defer out.Close()

for i in out.JSONMessages() {
...
}
...
```

Code after:
package client

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"iter"
	"net/url"
	"strings"
	"sync"

	cerrdefs "github.com/containerd/errdefs"
	"github.com/distribution/reference"
	"github.com/moby/moby/client/pkg/jsonmessage"
)

func newImagePullResponse(rc io.ReadCloser) ImagePullResponse {
	return ImagePullResponse{
		rc:    rc,
		close: &sync.Once{},
	}
}

type ImagePullResponse struct {
	rc    io.ReadCloser
	close *sync.Once
}

// Read implements io.ReadCloser
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() error {
	if r.close == nil {
		return nil
	}
	var err error
	r.close.Do(func() {
		if r.rc != nil {
			err = r.rc.Close()
Repository: moby/moby
File: client/image_pull.go (Go)

Code before:
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() (err error) {
	if r.rc != nil {
		err = r.rc.Close()
		r.rc = nil
	}
	return
}

// Messages decodes the response stream as a sequence of JSONMessages
func (r *ImagePullResponse) JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] {
	context.AfterFunc(ctx, func() {
		r.Close()
	})
	dec := json.NewDecoder(r)
	return func(yield func(jsonmessage.JSONMessage, error) bool) {
		defer r.Close()
		for {
			var jm jsonmessage.JSONMessage
			err := dec.Decode(&jm)
			if errors.Is(err, io.EOF) {
				break
			}
			if ctx.Err() != nil {
				yield(jm, ctx.Err())
				return
			}
			if !yield(jm, err) {
				return
			}
		}
	}
}

// ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// Caller can rely on ImagePullResponse#Messages() to monitor pull progress as a sequence of JSONMessages
// otherwise it's up to the caller to handle the [io.ReadCloser] and close it.
func (cli *Client) ImagePull(ctx context.Context, refStr string, options ImagePullOptions) (ImagePullResponse, error) {
	// FIXME(vdemeester): there is currently used in a few way in docker/docker
	// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
	// - if in trusted content, ref is used to pass the reference name, and tag for the digest
	//
	// ref; https://github.com/docker-archive-public/docker.engine-api/pull/162

	ref, err := reference.ParseNormalizedNamed(refStr)

Review comment (suggestion):
```suggestion
// Close implements io.ReadCloser
func (r *ImagePullResponse) Close() (err error) {
	if r.rc != nil {
		err = r.rc.Close()
		r.rc = nil
	}
	return
}
```

This needs a pointer receiver, otherwise the `r.rc = nil` will only be applied to the local copy

Code after:
	}
}

type ImagePullResponse struct {
	rc    io.ReadCloser
	close *sync.Once
}

// Read implements io.ReadCloser
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() error {
	if r.close == nil {
		return nil
	}
	var err error
	r.close.Do(func() {
		if r.rc != nil {
			err = r.rc.Close()
		}
	})
	return err
}

// JSONMessages decodes the response stream as a sequence of JSONMessages.
// if stream ends or context is cancelled, the underlying [io.Reader] is closed.
func (r ImagePullResponse) JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] {
	context.AfterFunc(ctx, func() {
		r.Close()
	})
	dec := json.NewDecoder(r)
	return func(yield func(jsonmessage.JSONMessage, error) bool) {
		defer r.Close()
		for {
			var jm jsonmessage.JSONMessage
			err := dec.Decode(&jm)
			if errors.Is(err, io.EOF) {
				break
			}
			if ctx.Err() != nil {
				yield(jm, ctx.Err())
				return
			}
			if !yield(jm, err) {
				return
			}
		}
	}
Repository: moby/moby
File: client/image_pull.go (Go)

Code before:
		close: &sync.Once{},
	}
}

type ImagePullResponse struct {
	rc    io.ReadCloser
	close *sync.Once
}

// Read implements io.ReadCloser
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() (err error) {
	if r.close == nil {
		return nil
	}
	r.close.Do(func() {
		if r.rc != nil {
			err = r.rc.Close()
		}
	})
	return
}

// Messages decodes the response stream as a sequence of JSONMessages
func (r ImagePullResponse) JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] {
	context.AfterFunc(ctx, func() {
		r.Close()
	})
	dec := json.NewDecoder(r)
	return func(yield func(jsonmessage.JSONMessage, error) bool) {
		defer r.Close()
		for {
			var jm jsonmessage.JSONMessage
			err := dec.Decode(&jm)
			if errors.Is(err, io.EOF) {
				break
			}
			if ctx.Err() != nil {
				yield(jm, ctx.Err())
				return
			}
			if !yield(jm, err) {
				return
			}
		}
	}
}

Review comment (suggestion):
Probably [best not to use](https://go.dev/wiki/CodeReviewComments#naked-returns:~:text=Corollary%3A%20it%E2%80%99s%20not%20worth%20it%20to%20name%20result%20parameters%20just%20because%20it%20enables%20you%20to%20use%20naked%20returns.%20Clarity%20of%20docs%20is%20always%20more%20important%20than%20saving%20a%20line%20or%20two%20in%20your%20function.) a named result & naked return, and just `var err error` in the body.

Code after:
		close: &sync.Once{},
	}
}

type ImagePullResponse struct {
	rc    io.ReadCloser
	close *sync.Once
}

// Read implements io.ReadCloser
func (r ImagePullResponse) Read(p []byte) (n int, err error) {
	return r.rc.Read(p)
}

// Close implements io.ReadCloser
func (r ImagePullResponse) Close() error {
	if r.close == nil {
		return nil
	}
	var err error
	r.close.Do(func() {
		if r.rc != nil {
			err = r.rc.Close()
		}
	})
	return err
}

// JSONMessages decodes the response stream as a sequence of JSONMessages.
// if stream ends or context is cancelled, the underlying [io.Reader] is closed.
func (r ImagePullResponse) JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] {
	context.AfterFunc(ctx, func() {
		r.Close()
	})
	dec := json.NewDecoder(r)
	return func(yield func(jsonmessage.JSONMessage, error) bool) {
		defer r.Close()
		for {
			var jm jsonmessage.JSONMessage
			err := dec.Decode(&jm)
			if errors.Is(err, io.EOF) {
				break
			}
			if ctx.Err() != nil {
				yield(jm, ctx.Err())
				return
			}
			if !yield(jm, err) {
				return
			}
		}