You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: api-remove.go
    path of file: ./repos/plik/vendor/github.com/minio/minio-go/v7
    
    the code of the file until where you have to start completion: /*
 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
 * Copyright 2015-2020 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package minio

import (
	"bytes"
	"context"
	"encoding/xml"
	"io"
	"net/http"
	"net/url"
	"time"

	"github.com/minio/minio-go/v7/pkg/s3utils"
)

//revive:disable

// Deprecated: BucketOptions will be renamed to RemoveBucketOptions in future versions.
type BucketOptions = RemoveBucketOptions

//revive:enable

// RemoveBucketOptions special headers to purge buckets, only
// useful when endpoint is MinIO
type RemoveBucketOptions struct {
	ForceDelete bool
}

// RemoveBucketWithOptions deletes the bucket name.
//
// All objects (including all object versions and delete markers)
// in the bucket wi
    
func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, resultCh chan<- RemoveObjectResult, opts RemoveObjectsOptions) {
	maxEntries := 1000
	finish := false
	urlValues := make(url.Values)
	urlValues.Set("delete", "")

	// Close result channel when Multi delete finishes.
	defer close(resultCh)

	// Loop over entries by 1000 and call MultiDelete requests
	for {
		if finish {
			break
		}
		count := 0
		var batch []ObjectInfo

		// Try to gather 1000 entries
		for object := range objectsCh {
			if hasInvalidXMLChar(object.Key) {
				// Use single DELETE so the object name will be in the request URL instead of the multi-delete XML document.
				removeResult := c.removeObject(ctx, bucketName, object.Key, RemoveObjectOptions{
					VersionID:        object.VersionID,
					GovernanceBypass: opts.GovernanceBypass,
				})
				if err := removeResult.Err; err != nil {
					// Version does not exist is not an error ignore and continue.
					switch ToErrorResponse(err).Code {
					case "InvalidArgument", "NoSuchVersion":
						continue
					}
					resultCh <- removeResult
				}

				resultCh <- removeResult
				continue
			}

			batch = append(batch, object)
			if count++; count >= maxEntries {
				break
			}
		}
		if count == 0 {
			// Multi Objects Delete API doesn't accept empty object list, quit immediately
			break
		}
		if count < maxEntries {
			// We didn't have 1000 entries, so this is the last batch
			finish = true
		}

		// Build headers.
		headers := make(http.Header)
		if opts.GovernanceBypass {
			// Set the bypass goverenance retention header
			headers.Set(amzBypassGovernance, "true")
		}

		// Generate remove multi objects XML request
		removeBytes := generateRemoveMultiObjectsRequest(batch)
		// Execute GET on bucket to list objects.
		resp, err := c.executeMethod(ctx, http.MethodPost, requestMetadata{
			bucketName:       bucketName,
			queryValues:      urlValues,
			contentBody:      bytes.NewReader(removeBytes),
			contentLength:    int64(len(removeBytes)),
			contentMD5Base64: sumMD5Base64(removeBytes),
			contentSHA256Hex: sum256Hex(removeBytes),
			customHeader:     headers,
		})
		if resp != nil {
			if resp.StatusCode != http.StatusOK {
				e := httpRespToErrorResponse(resp, bucketName, "")
				resultCh <- RemoveObjectResult{ObjectName: "", Err: e}
			}
		}
		if err != nil {
			for _, b := range batch {
				resultCh <- RemoveObjectResult{
					ObjectName:      b.Key,
					ObjectVersionID: b.VersionID,
					Err:             err,
				}
			}
			continue
		}

		// Process multiobjects remove xml response
		processRemoveMultiObjectsResponse(resp.Body, resultCh)

		closeResponse(resp)
	}
}